was ist so schlimm an globalen variablen?



  • ich habe jetzt in verschiedenen beiträgen gelesen, dass es als unfein gilt, globale variablen zu verwenden. nun frage ich mich, woher das kommt. was ist so schlimm daran? wenn ich z.b. einen int habe, der von verschiedenen funktionen manipuliert werden muss und ich ihn nicht global anlege, muss ich ja einen zeiger auf diesen durch alle funktionen "durchhangeln", selbst wenn die funktion selbst den int nicht manipuliert, sondern nur eine andere funktion aufruft, die das tut.

    void main()
    {
        int val;
    
        machwas(&val);
    }
    
    void machwas(int *pval)
    {
        machwasanderes(pval);
        //...
    }
    
    void machwasanderes(int *pval)
    {
        *pval *= 1;
    }
    

    das mag in diesem beispiel ja noch alles überschaubar sein, aber wenn ich erstmal funktionen habe, die vielleicht sagen wir 5 parameter erwarten und dann noch diesen zusätzlichen zeiger, den sie nur mittelbar benötigen, wirds unübersichtlich, wie ich finde.

    warum gilt es als unfein bzw. schlechten stil, es einfach so zu machen:

    int val;
    
    void main()
    {
        machwas();
    }
    
    void machwas(void)
    {
        machwasanderes();
        //...
    }
    
    void machwasanderes(void)
    {
        val *= 1;
    }
    

    oder hab ich mal wieder nix kapiert? 🤡

    mfg & danke



  • Habe gerade keine Zeit zu erklären, warum globale Variablen meist (nicht immer) scheiße sind, aber wenn du anstatt "int val;" "static int val;" benutzt, ist es keine globale Variable mehr und du kannst in der *.c Datei trotzdem von jeder Funktion auf die Variable zugreifen.



  • feigling schrieb:

    Habe gerade keine Zeit zu erklären, warum globale Variablen meist (nicht immer) scheiße sind, aber wenn du anstatt "int val;" "static int val;" benutzt, ist es keine globale Variable mehr und du kannst in der *.c Datei trotzdem von jeder Funktion auf die Variable zugreifen.

    ok das ist schonmal gut zu wissen. ich dachte bisher immer, static bewirkt nur, dass die variable nach funktionsende erhalten bleibt, aber nicht in allen funktionen "sichtbar" ist. wieder was gelernt, danke 🙂

    aber wenn jemand zeit / lust hätte, mir genauer zu erklären warum nicht global (hat das technische gründe oder nur ästhetische?) wäre das toll.

    mfg & danke



  • warum globale variablen sch... lecht sind?

    du siehst an einem call nicht mehr, welche variablen potenziell veraendert werden. das ist SCHLECHT.
    selbst wenn du selber da durchblicken solltest, jemand anderes wird sich nicht deine 100 globalen variablen merken, bevor er den code liest.

    edit: feigling, was redest du da?? global bleibt global.



  • okay, das ist tatsächlich ein nachvollziehbares argument. nun frage ich mich nur, nimmt man gewöhnlich für diesen übersichtsvorteil meines ersten beispiels auch den übersichtsnachteil dessen in kauf, dass zeiger übergeben werden müssen, die nur für weitere funktionsaufrufe innerhalb der ersten funktion benötig werden?
    denn wenn ich, wie feigling vorschlug, die variable static deklariere und dann ohne sie zu übergeben darauf zugreife ist es ja wieder wie bei der globalen variable, dass man nicht auf einen blick sieht, welche werte "machwas()" verändert.

    entschuldigt bitte, dass ich hier haare spalte, aber ich möchte diese grundlegenen dinge gerne vollständig verstehen. das erreiche ich am besten, finde ich, indem ich mit menschen darüber rede. danke für eure gedult 🙂

    mfg

    edit: wenn ich an "machwas()" einen zeiger übergebe, den "machwas()" nur an "machwasanderes()" weitergibt, werde ich da vom eigentlichen funktionsaufruf doch auch über die manipulierten werte getäuscht. somit ist der übersichtsvorteil auch wieder aufgehoben. oder sagt man dann quasi, dass die erste funktion den wert mittelbar manipuliert und damit ist es wieder nachvollziehbar(er)?



  • c.rackwitz schrieb:

    feigling, was redest du da?? global bleibt global.

    Dazu sollte man erst mal klären, was man unter 'global' verstehen möchte -- einen Variablenspezifizierer, der Variablen überall bekannt macht, kennt C schließlich nicht. Provokant: C kennt keine globalen Variablen.

    Dinge, die man potentiell global nennen könnte: external linkage, internal linkage, file scope, statische Lebenszeit, reservierte Namen ... usw.



  • nennen wir "global" alle variablen, die nicht in funktionen definiert sind.



  • Ich nenne "global" alle Variablen, auf die ich in anderen *.c Dateien mit extern zugreifen kann.



  • und wie nennst du dann vars, die ueberall in einer einzigen datei sichtbar sind?

    egal wie du die nennst, es ist trotzdem schlecht. definition hin oder her.



  • "Variablen, die nur in einer Source Datei sichtbar sind." 😉



  • also mir ist die definition des begriffs global im zusammenhang einer c-variable geläufig als im wesentlichen außerhalb von funktionen stattfindender deklarierung. aber da ich hier nicht versuche "global" zu definieren, sondern die globale verwendung von variablen und die übergabe durch zeiger gegenüberzustellen, wäre es toll wenn ihr mir in diesem zusammenhang weiterhelfen könntet.

    wie schon erwähnt, behaupte ich, dass das verwenden von zeigern als argument bzw. parameter auch nachteile in bezug auf die übersicht mit sich bringen kann. und da, wie ich verstanden habe, man globale variablen ablehnt, da sie der schnellen übersicht schaden, frage ich mich ob der vorteil von zeigern ggü. globals so gross ist, dass man die nachteile der zeigervariante einfach hinnimmt. oder gibt es für das problem in meinem ersten beispiel (s.h. erster beitrag) einfach nur bessere lösungen, die mir nicht bekannt sind?

    ich weiss, ich bin grad sehr kleinlich, aber ich möchte diese zusammenhänge einfach gern verstehen. möglicherweise verwirre ich mich auch selbst, indem ich elephanten aus mücken mache. es würde mir wirklich helfen, wenn mir jemand diese frage erläutern könnte, weil ich wahrscheinlich nur wieder alles falsch verstehe 😞



  • jule37 schrieb:

    also mir ist die definition des begriffs global im zusammenhang einer c-variable geläufig als im wesentlichen außerhalb von funktionen stattfindender deklarierung.

    Tja, und der nächste bezieht "global" nicht auf die Sichtbarkeit, sondern auf die Lebenszeit usw. usf. Vergessen wir den Begriff einfach.

    wie schon erwähnt, behaupte ich, dass das verwenden von zeigern als argument bzw. parameter auch nachteile in bezug auf die übersicht mit sich bringen kann. und da, wie ich verstanden habe, man globale variablen ablehnt, da sie der schnellen übersicht schaden, frage ich mich ob der vorteil von zeigern ggü. globals so gross ist, dass man die nachteile der zeigervariante einfach hinnimmt. oder gibt es für das problem in meinem ersten beispiel (s.h. erster beitrag) einfach nur bessere lösungen, die mir nicht bekannt sind?

    So ein Beispiel ist sinnlos, weil absolut unklar ist, wo welche Informationen überhaupt benötigt werden. Generell sollte man Variablen erst in der Funktion einführen, in der sie gebraucht werden.

    Und nein, Zeiger sind nicht unübersichtlich (auch dein Zeigerbeispiel ist nicht unbedingt unübersichtlich, das gibt sich, wenn man Zeiger öfter anwendet). In einem seriösen Programm versucht man die einzelnen "Programmmodule" (damit meine ich hier zB: Graphikausgabe, Programmlogik, Benutzerinteraktion, Netzwerkkram) unabhängig voneinander zu entwickeln. Das hilft zum einen, weil man dann einzelne Module unabhängig voneinander debuggen kann, zum anderen hat man nur ein Interface, mit dem dieses Modul mit der Aussenwelt kommunizieren. Es gibt nicht beliebig viele "globale Variablen", die deine Modulzustände steuern, sondern nur ein paar. In einem großen Projekt werden diese "globalen Variablen" dann recht schnell recht unübersichtlich viele, die den "globalen Namespace" (was immer das ist, je nach Definition) vollmüllen und immer mitdebuggt werden.

    Wenn das ganze Programm wirklich überall eine spezifische Variable benötigt, dann ist es aber schon okay, ihr external linkage zu verpassen, damit sie modulübergreifend sichtbar ist. Nur übertreiben sollte man das nicht, da man, siehe oben, Informationen so lokal wie möglich aufbewahren möchte. Deswegen sind viele "globale Variablen" häufig ein Hinweis auf ein schlampiges Design (Module nicht sauber voneinander abgegrenzt).



  • C hat ja normal nur Funktionen. Funktionen sind solche Dinger die Parameter entgegennehmen und ein Ergebniss liefern. Somit sollte man gleich sehen, welche Parameter eine Funktion benötigt und welches Ergebniss sie liefert.

    int machewas(void* parameter);

    Hier sehe ich sofort, das ein Parameter benötigt wird, und das die Funktion ein Ergebniss liefert. Der Name der Funktion beschreibt ausserdem, was die Funktion macht. Im günstigens Fall brauche ich weder den Code der Funktion zu kennen, noch eine Doku zu lesen.
    float sqrt(float x); Man sieht sofort was sie macht.

    void machewas(void);

    Hier muss ich erst den gesammten Code der Funktion lesen damit ich sehe was diese Funktion überhaupt an Parameter braucht und was für ein Ergebniss diese Funktion liefert.
    Ausserdem wenn man 1000 globale Variablen hat, woher soll man den wissen ob Variable xNummer455 nun von machewas() und xNummer235 von machewiederwas() benutzt wird. Man muss wieder in den Code von den Funktionen reinschauen.

    btw, static heist doch nur, dass diese Variable im gesammten Programm nur einmal existiert (im Speicher liegt).



  • Der Compiler kann bei globalen Variablen auch nicht ganz so aggressiv optimieren wie bei lokalen.

    Ich persönlich verwende globale Variablen nur wenn sie absolut notwendig, oder halt extrem geschickt (zum Debuggen z.B.) sind.



  • DEvent schrieb:

    btw, static heist doch nur, dass diese Variable im gesammten Programm nur einmal existiert (im Speicher liegt).

    Globale Variablen (also Variablen, die außerhalb von Funktionen deklariert wurden), bei denen static davor steht, sind nur in der Datei bekannt, in der sie daklariert wurden.



  • okay. saubere modultrennung kann ich als argument auch sehr gut verstehen. ich denke, ich komme der sache langsam näher. danke für euren rat.

    wenn ich euch richtig verstehe, wäre es somit z.b. sinnvoll, das handle zum hauptfenster einer applikation global zu machen, da man davon ausgehen kann, dass es ständig gebraucht wird. aber ein struct mit darstellungsoptionen sollte nur im grafikmodul rumgereicht werden.

    ja, ich glaub langsam kommt licht rein 🙂

    mfg & danke euch



  • Daniel E. schrieb:

    In einem seriösen Programm versucht man die einzelnen "Programmmodule" (damit meine ich hier zB: Graphikausgabe, Programmlogik, Benutzerinteraktion, Netzwerkkram) unabhängig voneinander zu entwickeln. Das hilft zum einen, weil man dann einzelne Module unabhängig voneinander debuggen kann, zum anderen hat man nur ein Interface, mit dem dieses Modul mit der Aussenwelt kommunizieren.

    stimmt. und jedes modul kann seine eigenen 'globalen' variablen haben (mit einem 'static' davor). das ist nix schlimmes.


Anmelden zum Antworten