Ich habe festgestellt, dass der Compiler nicht einmal eine Warnung ausgibt, wenn ich eine globale Variable mehrmals deklariere.
Wenn ich jedoch beispielsweise eine lokale Variable in einer Funktion mehrmals deklariere, gibt der gcc-Compiler einen Fehler aus und kompiliert die Datei nicht. (Ich frage in Bezug auf gcc, aber dies ist eher eine allgemeine Frage zum Sprachdesign, keine Frage zu gcc, da ich denke, dass es wahrscheinlich ist, dass sich andere Compiler ähnlich verhalten.)
Was ist die Erklärung für dieses Verhalten?
extern int x;
eine Deklaration hat, wird die Kompilierung abgebrochen, da der Variablen kein Speicherplatz zugewiesen ist.Antworten:
Nach Kodierungsrichtlinien :
Die lokale Variable hat keine Verknüpfung. Es gibt also einen Namen. Kollision tritt auf. Eine Mehrfachdeklaration der lokalen Variablen ist also nicht möglich.
Die globale Variable verfügt über eine externe Verknüpfung. Somit ist eine Mehrfachdeklaration globaler Variablen möglich.
quelle
@msc gibt eine gute Einführung in die Regeln hinter diesem Verhalten.
C hat drei Arten von globalen Deklarationen für Objekte, nämlich diejenigen, die es sind (und ich beschönige
static
hier):extern int a;
int a = 3;
oderextern int a = 3;
int a;
Es sind mehrere Deklarationen vom Typ 1 und 3 zulässig, während höchstens eine (Typ 2) Definition zulässig ist.
Wenn Sie auch nach der Motivation für diese Regeln fragen, wird eine separate Kompilierung unterstützt . (Siehe Übersetzungseinheit ).
Um ein Programm in mehrere Dateien separat kompilierten zu brechen, müssen wir ein paar Features, nämlich (a) die Lage zu , ohne notwendigerweise die Definition zu erklären , und (b) nach vorn Erklärung .
Innerhalb einer Übersetzungseinheit müssen wir in der Lage sein, auf globale Funktionen und Daten in einer anderen Übersetzungseinheit zu verweisen. Außerdem möchten wir hier eine Fehlerprüfung durchführen, um fehlende Definitionen und fehlerhafte doppelte Definitionen zu ermitteln.
Manchmal deklarieren wir in derselben Übersetzungseinheit eine globale und definieren sie später. Dies kann passieren, wenn wir aus irgendeinem Grund eine Vorwärtsdeklaration benötigen oder wenn wir eine gemeinsame Header-Datei (die Deklarationen bereitstellt) innerhalb einer Übersetzungseinheit verwenden, die auch explizite Definitionen bietet.
Da die separate Kompilierung in C durch Verknüpfung globaler Funktionen und Daten erfolgt, sind diese Funktionen auf globaler Ebene erforderlich, jedoch nicht auf lokaler Ebene.
Wie @msc hervorhebt, ist dies für lokale Variablen nicht erforderlich, da sie keine Verknüpfung haben.
C (wie viele andere Sprachen) bietet keine Verknüpfung für lokale Variablen, da die Sprache nicht versucht, eine einzelne Funktion zu unterstützen, die mehrere separate Übersetzungseinheiten umfasst.
(Natürlich kann eine Funktion mehrere Quelldateien umfassen, jedoch nicht mehrere Übersetzungseinheiten.)
Eine vorläufige Definition funktioniert genau wie eine Deklaration, da sie in mehreren Übersetzungseinheiten zulässig ist (und sich auch gut mit anderen Deklarationen kombinieren lässt). Wenn es jedoch im gesamten Programm keine (nicht vorläufige) Definition für den Bezeichner gibt, wird der Satz von (einer oder mehreren) vorläufigen Definitionen über mehrere Übersetzungseinheiten (für einen Bezeichner) als Definition für das Objekt verwendet, dessen Initialisierer ist Null.
Dies kann implementiert werden, indem diese mit der richtigen Größe und Ausrichtung in den Abschnitt .BSS eingefügt werden . Der Linker passt sie entweder an die wahre Definition an, wenn sie gefunden werden, oder passt sie aneinander an, sodass sie in BSS auf Null gesetzt werden.
Der Begriff der getrennten Zusammenstellung kann vollständig ohne das Merkmal vorläufiger Definitionen unterstützt werden - ich denke, vorläufige Definitionen gibt es hauptsächlich aus historischen Gründen. (Ich sage nicht, dass sie nicht nützlich sind, nur wenn die Sprache heute erstellt wurde, könnte dies als unnötig angesehen werden und daher nicht angeboten werden.)
quelle