Warum erlaubt C mehrere globale Deklarationen derselben Variablen, aber NICHT mehrere lokale Deklarationen?

8

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?

yoyo_fun
quelle
Nur um sicher zu gehen, hatte Ihre globale Variable immer den gleichen Typ, oder?
Walfrat
@Walfrat Ja, die Variable wird immer vom selben Typ deklariert. Wenn zwei Variablen mit demselben Namen, aber unterschiedlichem Typ global deklariert werden, gibt der gcc den Fehler "widersprüchliche Typen für eine (Variable)" aus
yoyo_fun
3
Sie können eine lokale Variable nicht einmal deklarieren. Sie können es nur definieren. Das Deklarieren einer Variablen sagt dem Compiler, was es ist. Das Definieren einer Variablen weist den Compiler an, Speicher dafür zuzuweisen. Sie müssen alle Variablen definieren. In C kann eine Definition einer globalen Variablen mehrfach für eine Deklaration verwendet werden. Wenn das Programm jedoch nur extern int x;eine Deklaration hat, wird die Kompilierung abgebrochen, da der Variablen kein Speicherplatz zugewiesen ist.
Shawnhcorey

Antworten:

11

Nach Kodierungsrichtlinien :

In dem Satz von Übersetzungseinheiten und Bibliotheken, die ein gesamtes Programm bilden, bezeichnet jede Deklaration eines bestimmten Bezeichners mit externer Verknüpfung dasselbe Objekt oder dieselbe Funktion. Innerhalb einer Übersetzungseinheit bezeichnet jede Deklaration eines Bezeichners mit interner Verknüpfung dasselbe Objekt oder dieselbe Funktion. Jede Deklaration eines Bezeichners ohne Verknüpfung bezeichnet eine eindeutige Entität.

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.

msc
quelle
7
Diese Antwort ist in Ordnung, aber die offensichtliche Folgefrage lautet dann: Was ist der Grund für diese Definition?
Doc Brown
Bei vielen C-Macken lautet das Grundprinzip "C-Compiler vor dem Standard haben es einfach so gemacht". Wenn Sie sich die Komplexität der "vorläufigen Definition" ansehen, ist es ziemlich wahrscheinlich, dass dies hier der Fall ist.
Sebastian Redl
9

@msc gibt eine gute Einführung in die Regeln hinter diesem Verhalten.

Ich habe festgestellt, dass der Compiler nicht einmal eine Warnung ausgibt, wenn ich eine globale Variable mehrmals deklariere.

C hat drei Arten von globalen Deklarationen für Objekte, nämlich diejenigen, die es sind (und ich beschönige statichier):

  1. Erklärungen, die keine Definitionen sind - extern int a;
  2. Erklärungen, die auch Definitionen sind - int a = 3;oderextern int a = 3;
  3. vorläufige Definitionen - int a;

Es sind mehrere Deklarationen vom Typ 1 und 3 zulässig, während höchstens eine (Typ 2) Definition zulässig ist.


Was ist die Erklärung für dieses Verhalten?

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.)

Erik Eidt
quelle