Sind statische Variablen im Dateibereich in C genauso schlecht wie globale globale Variablen?


8

In C würden Sie häufig / manchmal (aus Stilgründen) eine Dateibereichsvariable verwenden static, in der Sie eine private Klassenmitgliedsvariable in C ++ verwenden würden. Wenn Sie auf Multithread-Programme skalieren, passt das einfache Hinzufügen thread_localvon C11 oder der lang unterstützten Erweiterung __threadgut. Ich weiß, dass Sie in C genau das Gleiche tun können wie in C ++, indem Sie alles in a einfügen structund eine Reihe von Funktionen erstellen, die structals erstes Argument einen Zeiger darauf verwenden . Einige Bibliotheken tun dies ausgiebig. Aber mein persönlicher Stil ist structes, bei Bedarf so klein wie möglich zu halten .

Ich lese oder höre oft Leute, die argumentieren, dass 'globale' Variablen so schlecht sind. Ich folge ihren Gründen, und die meisten ihrer Argumente scheinen sich auf externglobale Variablen in C-Begriffen zu beziehen . Was sie sagen, ist sicherlich wahr. Ich verwende manchmal 1 oder 2 externdeklarierte Variablen im gesamten Programm, wenn dies die Dinge erheblich vereinfacht und wenn es einfach ist, sie im Auge zu behalten, aber wenn Sie weiter gehen, wird ein Programm leicht unvorhersehbar.

Was ist mit staticVariablen? Haben sie immer noch das gleiche Problem wie "echte" globale Variablen? Vielleicht muss ich diese Frage nicht einmal stellen und weitermachen, wenn ich denke, dass das, was ich tue, richtig ist, aber heute habe ich einen anderen Beitrag vom Typ "Globale Variablen sind SCHLECHT" gesehen und bin schließlich hierher gekommen und habe gedacht, dass dies vielleicht richtig ist Platz für solche Fragen. Was ist dein Gedanke?

Diese Frage ist kein Duplikat davon, da in dieser Frage nach externund staticnicht lokalen Variablen gefragt wird, während sich die andere Frage auf Variablen für den Dateibereich und den Blockbereich staticbezieht.



3
Ich denke nicht, dass dies ein Duplikat ist. Diese Frage bezieht sich auf eine dateistatische Variable im Vergleich zu einer externen statischen (globalen) Variablen. Die andere Frage ist der Vergleich funktionsstatischer Variablen mit globalen Variablen.

@gnat Dies ist keine doppelte Frage. Ich habe eine Bearbeitung vorgenommen, um zu erklären, was Snowman in seinem Kommentar gesagt hat. Auch der Titel ist anders.
Xiver77

@ xiver77 Während es derzeit keine Stimmen gibt, die als Duplikat geschlossen werden könnten, könnten einige der Antworten auf die andere Frage hier aufschlussreich sein.

@Snowman nach meiner Lektüre, akzeptierte Antwort in dieser anderen Frage deckt alle drei Fälle ab (es scheint zu erklären, wann und warum Dateibereichsstatik gegenüber funktionalen und globalen zu bevorzugen ist)
Mücke

Antworten:


17

In einem gut gestalteten C-Programm ähnelt eine dateistatische Variable einem privaten statischen Mitglied einer Klasse:

  • Auf sie kann nur von Funktionen in dieser Datei zugegriffen werden, ähnlich wie auf eine private statische Mitgliedsvariable nur von Funktionen in der Klasse zugegriffen werden kann, in der sie definiert ist.

  • Es gibt nur eine Kopie der Variablen.

  • Seine Lebensdauer ist die Programmlebensdauer.

Eine externVariable wäre eine echte globale Variable wie in jeder Sprache, die sie unterstützt.

Eine staticnicht globale Variable ist nicht so schlecht wie eine globale. in der Tat sind sie in einigen Fällen notwendig.

  • Der Zugriff wird über die von Ihnen geschriebenen Funktionen gesteuert. Dies hilft bei der Datenintegrität, einschließlich der Überprüfung der Grenzen sowie der Thread-Sicherheit. (Hinweis: Dies garantiert keine Gewindesicherheit, es ist lediglich ein Hilfsmittel auf dem Weg)

  • Daten sind gekapselt: Nur diese Datei kann darauf zugreifen. Dies ist so nah wie C an der Kapselung, bei der mehrere Funktionen auf eine statische Variable zugreifen können.

Globale Variablen sind auf jeden Fall schlecht. Statische Dateivariablen haben die Vorteile einer privaten statischen Variablen, aber keinen der Nachteile einer globalen Variablen.

Das einzige Problem ist, dass andere Dateien im Gegensatz zu einer echten privaten statischen Variablen wie in C ++ eine externVariable deklarieren können, die der Deklaration entspricht, und Sie den Zugriff nicht verhindern können. Mit anderen Worten, Sie verlassen sich auf das Ehrensystem, um zu vermeiden, dass es zu einer globalen Variablen wird.


6

Der globale Status, einschließlich externVariablen und Nichtvariablen const staticim Dateibereich oder in Funktionen, kann häufig eine einfache Lösung für ein bestimmtes Problem sein, es gibt jedoch drei Probleme:

  1. staticmacht Code nicht testbar , da staticVariablen in der Regel nicht ersetzbare Abhängigkeiten sind. Oder in mehr OOP-y-Worten: Sie folgen nicht dem Prinzip der Abhängigkeitsinversion. Ich bin aus dynamischen Sprachen wie Perl zu C und C ++ gekommen, daher ist mein Kostenmodell auf virtuelle Versand- und Funktionszeiger usw. ausgerichtet. Bei den aktuellen Sprachen gibt es einen Konflikt zwischen Testbarkeit und guter Architektur, aber ich denke, dass das kleine Ärgernis, Ihre Abhängigkeiten explizit zu machen und sie in Tests überschreiben zu lassen, durch die einfache Schreibbarkeit von Tests spürbar ausgeglichen wird und somit sicherstellt, dass Ihre Software funktioniert erwartet. Ohne Ihren Code dynamischer zu gestalten, ist der einzige verfügbare Mechanismus zum Einfügen von Abhängigkeiten für einen Test die bedingte Kompilierung.

  2. Der globale Zustand macht es schwierig, über Korrektheit nachzudenken , und das führt zu Fehlern. Je mehr Teile auf eine Variable zugreifen und diese ändern können, desto einfacher ist es, den Überblick über das Geschehen zu verlieren. Stattdessen: lieber einzelne Zuordnung von Variablen! Lieber constwo immer vernünftig! Ziehen Sie es vor, Variablen durch Getter und Setter zu schützen, in denen Sie Korrektheitsprüfungen einführen können. Solange der Staat ist staticund nicht extern, ist es immer noch möglichum die Korrektheit aufrechtzuerhalten, aber es ist immer besser anzunehmen, dass ich in einer Woche nicht so schlau bin wie ich. Insbesondere in C ++ können wir Klassen verwenden, um verschiedene Abstraktionen zu modellieren, die es unmöglich machen, etwas zu missbrauchen. Versuchen Sie also, das Typsystem anstelle Ihrer Intelligenz zu verwenden - Sie müssen über wichtigere Dinge nachdenken.

  3. Der globale Status kann bedeuten, dass Ihre Funktionen nicht erneut eingegeben werden oder dass sie jeweils nur in einem Kontext verwendet werden können. Stellen Sie sich einen Datenbanktreiber vor, der nur eine Verbindung verwalten kann! Das ist eine völlig unnötige Einschränkung. In der Realität sind die Einschränkungen häufig subtiler, z. B. eine globale Variable, mit der Ergebnisse aggregiert werden. Machen Sie stattdessen Ihren Datenfluss explizit und übergeben Sie alles über Funktionsparameter. Auch hier können C ++ - Klassen dies leichter handhaben.

Offensichtlich static const NAMED_CONSTANTSsind OK. Die Verwendung staticinnerhalb von Funktionen ist viel schwieriger: Während es für träge initialisierte Konstanten nützlich ist, kann es ziemlich unprüfbar sein. Ein Kompromiss besteht darin, die Berechnung des Anfangswertes von der statischen Variablen zu trennen, damit beide Teile separat getestet werden können.

In kleinen, in sich geschlossenen Programmen spielt dies alles keine Rolle, und Sie können den staticStatus weiterhin nach Herzenslust verwenden. Wenn Sie jedoch ungefähr 500 LOC überschreiten oder eine wiederverwendbare Bibliothek schreiben, sollten Sie wirklich über eine gute Architektur und eine gute Benutzeroberfläche ohne unnötige Einschränkungen nachdenken.


Einige Ihrer Vorschläge zu Design und Sicherheit können in Programmen, die in C geschrieben werden müssen, manchmal nicht berücksichtigt werden.
xiver77

Und der globale Zustand ist nicht unbedingt fadenunfreundlich. Der neueste C- und C ++ - Standard wurde bereits von thread_localCompilern als Erweiterung vor der Standardisierung unterstützt.
Xiver77

Um viele der von Ihnen erwähnten Probleme des globalen Zustands zu vermeiden, haben die meisten gut geschriebenen C-Programme eine flache und transparente Struktur mit minimierten äußeren Abhängigkeiten.
Xiver77

Nur wenn der Code statisch und die Daten veränderbar bleiben, ist dies die einzige Möglichkeit, das effizienteste Programm zu schreiben, das in der aktuellen Computerarchitektur möglich ist.
Xiver77

@ xiver77 Ich habe den Luxus, mehr Code auf hoher Ebene zu schreiben, daher ist es in meiner Arbeit weder notwendig, die Architektur für die Leistung zu opfern noch C zu verwenden :) Beim Schreiben von C fällt es mir viel schwerer, den richtigen Code und die Wahl zu schreiben Die Auswahl geeigneter Abstraktionen unterscheidet sich von dem, was ich bevorzugen würde, aber es ist immer noch möglich, viel Sicherheit zu bieten. Meine Antwort versucht, C ++ - spezifische Ideen klar als solche zu kennzeichnen. Ihr Standpunkt zu kleinen Dateien ist sehr gut, was es einfacher macht, über das Programm nachzudenken, und das Problem der staticVariablen reduziert, aber nicht beseitigt .
Amon

1

Ich halte Variablen mit Dateibereich nicht für so schlecht wie globale Variablen. Schließlich sind alle Zugriffe auf diese Variablen auf eine einzige Quelldatei beschränkt. Mit dieser Einschränkung sind Dateibereichsvariablen so gut oder schlecht wie ein privates statisches C ++ - Datenelement, und Sie verbieten ihre Verwendung nicht, oder?


1
In C ++ ermutigt Sie die Syntax dazu, viele Elementvariablen in Klassen einzufügen, sodass ein privates statisches Element nicht oft erforderlich ist. Wenn Sie in C jedoch nicht vollständig emulieren möchten, was Sie mit einer C ++ - Klasse tun würden, können statische oder thread_local-Variablen anstelle eines Strukturelements verwendet werden, wenn Sie vermeiden möchten, den Strukturzeiger überall zu übergeben. Meine Frage ist dazu.
Xiver77

Ich spreche von Mitgliedern mit staticSpeicher, die genau einmal existieren, nicht für jedes Objekt. Diese Variable kann nicht braucht eine Instanz der Klasse, um durch den Code der Klasse referenziert zu werden, so gibt es keine Notwendigkeit, übergeben Sie einen Verweis / Zeiger auf einen Singleton um. Genau das erreichen auch Dateibereichsvariablen. Der einzige Unterschied besteht darin, dass das staticMitglied einen Klassenbereich hat, während die static"globale" Variable einen Dateibereich hat. Aber diese beiden Bereiche sind in ihrem Ausmaß sehr ähnlich, was mein Punkt ist. Ich stimme jedoch zu, dass die verschiedenen Bedeutungen von staticverwirrend sind.
cmaster

1
Zumindest in C hat statisch wirklich eine Bedeutung für Variablen (nicht für Funktionen).
Xiver77

1

Meiner Ansicht nach hängt alles vom Umfang der Variablen ab (nicht konstant, etwas Veränderliches). Es ist eine Ansicht, der zwar einige Nuancen fehlen, aber es ist ein pragmatischer Gegenpol und ein Appell, auf die grundlegendsten Grundlagen für diejenigen zurückzuarbeiten, die sagen: "Das ist absolut böse!" nur um dann auf Themen zu stoßen, die denen ähneln, die mit dem verbunden sind, was sie kritisieren, wie z. B. die Rennbedingungen.

Stellen Sie sich vor, Sie haben eine 50.000-Zeilen-Funktion mit allen Arten von Variablen, die oben deklariert sind, und gotoAnweisungen, mit denen Sie überall herumhüpfen können . Das ist bei einem solch monströsen Variablenumfang nicht sehr angenehm, und es wird äußerst schwierig sein, über die Funktion und die Vorgänge mit solchen Variablen nachzudenken. In solch einem monströsen Fall verliert die normale Unterscheidung zwischen "äußerer" und "innerer" Nebenwirkung viel von ihrem praktischen Zweck.

Stellen Sie sich vor, Sie haben ein einfaches Programm mit 80 Zeilen, das Sie nur einmal schreiben und mit einer globalen Variablen starten (entweder mit interner Verknüpfung und Dateibereich oder externer Verknüpfung, aber so oder so ist das Programm winzig). Das ist nicht so schlecht.

Stellen Sie sich vor, Sie haben eine monströse Klasse in einer objektorientierten Sprache, die die Logik Ihres gesamten Programms mit Tausenden und Abertausenden von Codezeilen für die Implementierung enthält. In diesem Fall sind die Mitgliedsvariablen problematischer als die globalen Variablen im obigen Programm mit 80 Zeilen.

Wenn Sie in der Lage sein möchten, Ihren Code besser und sicherer zu beurteilen, die Thread-Sicherheit (oder das Fehlen davon) besser vorhersehbar zu machen, sicherzustellen, dass Ihre Tests eine gute Abdeckung aufweisen, ohne dass alle Arten von potenziellen Randfällen übersehen werden usw. Dann hilft es, den Zugriff auf Variablen einzugrenzen.

Die Statik des Dateibereichs hat tendenziell einen engeren Bereich als die mit externer Verknüpfung. Wenn Ihre Quelldatei jedoch 100.000 Codezeilen umfasst, ist sie immer noch verdammt breit. Wenn Sie sie für die Statik des Dateibereichs nicht vermeiden können, würde ich versuchen, ihren Gültigkeitsbereich eng zu halten, indem Sie Ihre Quelldatei, die auf sie zugreifen kann, nicht riesig machen, da in diesem Fall die Reduzierung des Gültigkeitsbereichs eine Reduzierung der Größe und des Entwurfsbereichs bedeutet der Quelldatei im Gegensatz zur Funktion (für lokale Variablen, einschließlich Parameter), Klasse (für Mitgliedsvariablen) oder möglicherweise Modul (für Globals mit externer Verknüpfung, aber nur innerhalb des Moduls zugänglich) oder sogar der gesamten Software (für Globals mit externe Verknüpfung für die gesamte Software zugänglich).

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.