Ist das Übergeben globaler Variablen an Funktionen problematisch?
Lesezeit: 7 Minuten
Magisch
Betrachten Sie die folgende Funktionsdeklaration:
int abmeld(char *strsend)
das heißt so
abmeld(str);
wo Str ist eine globale Variable, die am Anfang der Programmdatei (nach den Includes) wie folgt deklariert und initialisiert wird:
char str[300] = "";
Jetzt weiß ich bereits, dass dies unnötiger Code ist (Sie können von jeder Funktion aus auf das char-Array zugreifen und es ändern, ohne es sowieso zu übergeben), aber ist das eigentlich sonst problematisch?
Gibt es Konsequenzen (wie Möglichkeiten für schwerwiegende Fehler oder undefiniertes Verhalten), die auftreten können, wenn eine bereits global gültige Variable an eine Funktion übergeben wird?
Die Funktion kümmert sich nicht darum, woher der Parameter kommt.
– Micha Wiedenmann
10. Februar 2016 um 7:54 Uhr
Ein Zeiger ist ein Zeiger. Es spielt keine Rolle, welchen Gültigkeitsbereich die angegebene Variable hat. Übrigens würde ich vorschlagen, die globale Statik zu erstellen: static char str[300] = {0};
– LPs
10. Februar 2016 um 7:55 Uhr
Was meinst du mit “problematisch”? Wenn Sie unnötiges oder möglicherweise schlechtes Design meinen, lautet die Antwort ja. Wenn Sie meinen, dass es nicht funktionieren wird, dann nein, es wird tatsächlich funktionieren.
– DarioP
10. Februar 2016 um 7:57 Uhr
@Magisch: Ihre Erwähnung von UB sollte in die Frage eingehen, nicht in Kommentare
– Basile Starynkevitch
10. Februar 2016 um 8:15 Uhr
Nebenproblem: Anrufen abmeld(char *strsend) mit char str[300] ist an sich ein potenzielles Problem, da abmeld()was sich ändern kann str[], kennt die Größe des Arrays nicht. Ich würde erwarten abmeld(const char *strsend) oder abmeld(char *strsend, size_t size).
– chux – Wiedereinsetzung von Monica
10. Februar 2016 um 15:18 Uhr
Basile Starynkevitch
Ich würde das Gegenteil sagen, es ist fast nie problematisch, ein Global an eine Funktion zu übergeben (und es ist normalerweise schmutzig, viele Globals zu verwenden, da der Code unlesbar wird).
Eine Funktion, die leicht (oder überhaupt nicht) vom globalen Zustand abhängt, ist oft besser lesbar und verständlicher als eine Funktion, die viele globale (oder sogar statische) Variablen verwendet. Eine in vielen Funktionen geänderte globale Variable macht Ihr Programm unübersichtlich.
(vergiss nie, dass du nicht nur für den Computer programmierst, sondern auch für deine Kollegen – vielleicht sogar dich selbst in ein paar Monaten – die deinen Quellcode verbessern müssten)
Auch Funktionen, die den globalen Zustand verwenden, sind dies normalerweise nicht wiedereintretend.
Zu guter Letzt, undefiniertes Verhalten ist meistens orthogonal zu globalen vs. Argumentdaten. Insbesondere ein Pufferüberlauf kann sowohl mit einer globalen Variablen als auch mit einem Zeiger auf ein Array (z. B. ein Argument oder eine lokale Variable) auftreten.
Eine sehr grobe Faustregel wäre, das Gehirn des Entwicklers nicht mit mehr als 7 Elementen zu belasten (magische Zahl 7, + oder – 2); daher die Folkloreregel, mehr als 7 Argumente oder mehr als 7 Globals zu vermeiden.
Globale Konstanten sind in dieser Hinsicht viel weniger schädlich – sie wirken sich beispielsweise nicht auf den Wiedereintritt aus.
– MSalter
10. Februar 2016 um 12:29 Uhr
zwöl
Dort ist ein Fall, in dem dies problematisch sein könnte: if abmeld macht schon was mit str global. Als triviales Beispiel:
dann abmeld(str) hat undefiniertes Verhalten, weil snprintf hat ein undefiniertes Verhalten, wenn sein Zielpuffer einen seiner Eingänge überlappt.
Dies zeigt einen der Gründe, warum globale Variablen problematisch sind: um zu wissen, was sicher als Argument übergeben werden kann abmeldman muss nicht nur wissen, dass es an schreibt str (was sicher dokumentiert wäre), aber wie es das macht – es hätte geschrieben werden können
und dann hätte es ein wohldefiniertes Verhalten, egal was passiert s zeigt auf, solange es sich um einen gültigen C-String handelt.
Giorgi Moniava
Jetzt weiß ich bereits, dass dies unnötiger Code ist (Sie können von jeder Funktion aus auf das char-Array zugreifen und es ändern, ohne es sowieso zu übergeben), aber ist das eigentlich sonst problematisch?
Dabei spielt es für die Funktion keine Rolle, ob sie lokal oder global definierte Variable empfängt. Probleme mit globalen Variablen hängen manchmal mit der Tatsache zusammen, dass Sie möglicherweise nicht wissen, von welchen Teilen des Programms Sie zugreifen/ihren Wert ändern. Thread-Sicherheit ist möglicherweise auch relevant.
Das fragliche Programm hat kein Threading und nur eine Programmdatei, aber trotzdem danke für den Hinweis.
– Magisch
10. Februar 2016 um 7:56 Uhr
MSalter
Es ist sehr, SEHR üblich, globale Werte an Funktionen zu übergeben. Beispiel:
const char* global = "Example";
void foo() {
printf("%s\n", global );
}
Offensichtlich übergibt dies ein globales an printf. Die C-Sprache von Entwurf macht diese Verwendung sicher. Eine fehlerhafte Implementierung, die darüber stolpert, würde schnell ausgerufen werden.
Abhinet
Nein überhaupt nicht.
Jetzt weiß ich bereits, dass dies unnötiger Code ist
Nicht immer. Falls Ihre Funktion kein Standardargument hat, müssen Sie sich an den Funktionsprototypen halten und die globale Variable übergeben. Der Funktion ist es jedoch egal, ob der Zeiger auf eine lokale oder globale Variable zeigt.
/* main.c */
char str[300] = {0};
int abmeld(char *strsend)
{
/* Do something...process strsend */
return 0;
}
int main( void )
{
abmeld(str); /*Cannot pass void here as abmeld expects a char* */
char localstr[10] = {0};
abmeld(localstr);
return 0;
}
Könnten Sie den Code vervollständigen, um zu demonstrieren, wann wir die Funktionssyntax besser einhalten müssen?
– nalzok
10. Februar 2016 um 8:40 Uhr
Jaffer Wilson
Sie möchten der Funktion eine globale Variable übergeben. Es ist einfach, dass die Funktion, die Sie verwenden, Parameter erfordert, dann müssen Sie die Parameter des Typs des Arguments übergeben, der in der Funktion erforderlich ist.
Hier gibt es keine Bedenken oder Probleme beim Übergeben einer globalen Variablen oder einer lokalen Variablen. Dabei ist auf den Datentyp des zu übergebenden Arguments zu achten.
Könnten Sie den Code vervollständigen, um zu demonstrieren, wann wir die Funktionssyntax besser einhalten müssen?
– nalzok
10. Februar 2016 um 8:40 Uhr
Anzeigename
Die Methode abmeld(char *) soll nur das ihm zur Verfügung gestellte Argument modifizieren/arbeiten. Es mag zwar schlecht sein, eine globale Variable an diese Methode zu übergeben, aber das verbietet niemandem, diese Methode mit einem anderen char * aufzurufen.
Wenn diese Methode beispielsweise prüft, ob die Zeichenfolge, auf die gezeigt wird, ein Palindrom ist, dann ist das Schreiben dieser Methode ein Beispiel für eine gute Codierung. Jetzt kann jeder es jedes Mal aufrufen, wenn er/sie wissen möchte, ob die Zeichenfolge ein Palindrom ist oder nicht.
Jetzt weiß ich bereits, dass dies unnötiger Code ist (Sie können von jeder Funktion aus auf das char-Array zugreifen und es ändern, ohne es sowieso zu übergeben), aber ist das eigentlich sonst problematisch?
Es darf kein unnötiger Code sein, wie oben erklärt. Der Zweck des Schreibens einer neuen Methode besteht darin, eine Arbeit aufzuteilen. Mit anderen Worten, eine Methode sollte nur tun eine Sache. Es sei denn, die Methode abmeld(char *) geschrieben wurde, um ausschließlich diese bestimmte globale Variable zu modifizieren (und selbst das kann eine gute Sache sein), ist der Code so, wie er geschrieben wurde, vollkommen in Ordnung, solange er es tut eine Sache mit dem dafür vorgesehenen Argument.
Es gibt zahlreiche Beispiele, bei denen dieser Code problematisch sein kann, und die Probleme sind intuitiv. Beispielsweise kann es mehr Methoden geben, die den globalen String modifizieren/bearbeiten. Aber diese Probleme sind die Probleme, die auftreten, wenn Sie eine globale Variable verwenden. Um diese Probleme zu beseitigen, müssen Sie die globale Variable und nicht die Methode entfernen, da es nicht die Schuld der Methode ist, dass sie mit einer globalen Variablen verwendet wird.
Gibt es Konsequenzen (wie Möglichkeiten für schwerwiegende Fehler oder undefiniertes Verhalten), die auftreten können, wenn eine bereits global gültige Variable an eine Funktion übergeben wird?
Das kann ich nicht pauschal sagen, aber ich kenne keine. Ich habe auch kein Buch gelesen, das davon abgeraten hat, globale Variablen an Funktionen zu übergeben.
13441100cookie-checkIst das Übergeben globaler Variablen an Funktionen problematisch?yes
Die Funktion kümmert sich nicht darum, woher der Parameter kommt.
– Micha Wiedenmann
10. Februar 2016 um 7:54 Uhr
Ein Zeiger ist ein Zeiger. Es spielt keine Rolle, welchen Gültigkeitsbereich die angegebene Variable hat. Übrigens würde ich vorschlagen, die globale Statik zu erstellen:
static char str[300] = {0};
– LPs
10. Februar 2016 um 7:55 Uhr
Was meinst du mit “problematisch”? Wenn Sie unnötiges oder möglicherweise schlechtes Design meinen, lautet die Antwort ja. Wenn Sie meinen, dass es nicht funktionieren wird, dann nein, es wird tatsächlich funktionieren.
– DarioP
10. Februar 2016 um 7:57 Uhr
@Magisch: Ihre Erwähnung von UB sollte in die Frage eingehen, nicht in Kommentare
– Basile Starynkevitch
10. Februar 2016 um 8:15 Uhr
Nebenproblem: Anrufen
abmeld(char *strsend)
mitchar str[300]
ist an sich ein potenzielles Problem, daabmeld()
was sich ändern kannstr[]
, kennt die Größe des Arrays nicht. Ich würde erwartenabmeld(const char *strsend)
oderabmeld(char *strsend, size_t size)
.– chux – Wiedereinsetzung von Monica
10. Februar 2016 um 15:18 Uhr