External and tentative definitions
Auf der obersten Ebene einer Translation Unit (d.h. einer Quelldatei mit allen #includes nach dem Präprozessor) ist jedes C-Programm eine Folge von Deklarationen , die Funktionen und Objekte mit externer oder interner Verknüpfung deklarieren. Diese Deklarationen werden als externe Deklarationen bezeichnet, da sie außerhalb jeglicher Funktion erscheinen.
extern int n; // externe Deklaration mit externem Linkage int b = 1; // externe Definition mit externem Linkage static const char *c = "abc"; // externe Definition mit internem Linkage int f(void) // externe Definition mit externem Linkage { int a = 1; // nicht extern return b; } static void x(void) // externe Definition mit internem Linkage { }
Mit externen Deklarationen deklarierte Objekte haben eine statische Speicherdauer und können daher nicht die Spezifizierer auto oder register verwenden , außer dass auto für Typinferenz verwendet werden kann (seit C23) . Die durch externe Deklarationen eingeführten Bezeichner haben Dateigültigkeitsbereich .
Inhaltsverzeichnis |
Vorläufige Definitionen
Eine vorläufige Definition ist eine externe Deklaration ohne Initialisierer und entweder ohne einen Speicherklassenspezifizierer oder mit dem Spezifizierer static .
Eine tentative definition ist eine Deklaration, die möglicherweise als Definition fungiert oder auch nicht. Falls eine tatsächliche externe Definition früher oder später in derselben Übersetzungseinheit gefunden wird, dann fungiert die tentative definition lediglich als Deklaration.
int i1 = 1; // Definition, externer Linkage int i1; // Tentative Definition, fungiert als Deklaration da i1 definiert ist extern int i1; // Deklaration, bezieht sich auf die vorherige Definition extern int i2 = 3; // Definition, externer Linkage int i2; // Tentative Definition, fungiert als Deklaration da i2 definiert ist extern int i2; // Deklaration, bezieht sich auf die externe Linkage-Definition
Wenn es keine Definitionen in derselben Übersetzungseinheit gibt, dann wirkt die tentative Definition als tatsächliche Definition, die das Objekt leer-initialisiert .
int i3; // tentativer Definition, externer Linkage int i3; // tentativer Definition, externer Linkage extern int i3; // Deklaration, externer Linkage // in dieser Übersetzungseinheit wird i3 definiert als ob durch "int i3 = 0;"
Im Gegensatz zu extern Deklarationen, die die Verknüpfung eines Identifikators nicht ändern, wenn eine vorherige Deklaration sie festgelegt hat, können vorläufige Definitionen in der Verknüpfung mit einer anderen Deklaration desselben Identifikators in Konflikt stehen. Wenn zwei Deklarationen für denselben Identifikator im Gültigkeitsbereich sind und unterschiedliche Verknüpfung aufweisen, ist das Verhalten undefiniert:
static int i4 = 2; // Definition, interne Verknüpfung int i4; // Undefiniertes Verhalten: Verknüpfungskonflikt mit vorheriger Zeile extern int i4; // Deklaration, bezieht sich auf die Definition mit interner Verknüpfung static int i5; // Tentative Definition, interne Verknüpfung int i5; // Undefiniertes Verhalten: Verknüpfungskonflikt mit vorheriger Zeile extern int i5; // Bezieht sich auf die vorherige, deren Verknüpfung intern ist
Eine vorläufige Definition mit internem Linkage muss einen vollständigen Typ haben.
static int i[]; // Fehler, unvollständiger Typ in einer statischen vorläufigen Definition int i[]; // OK, entspricht int i[1] = {0}; sofern nicht später in dieser Datei neu deklariert
One-Definition-Regel
Jede Übersetzungseinheit darf null oder eine externe Definition jedes Bezeichners mit interner Bindung (einem static Global) haben.
Wenn ein Bezeichner mit interner Verknüpfung in einem Ausdruck verwendet wird, der kein
Nicht-VLA,
(seit C99)
sizeof
,
_Alignof
(seit C11)
(bis C23)
,
alignof
(seit C23)
oder
typeof
(seit C23)
ist, muss es genau eine externe Definition für diesen Bezeichner in der Übersetzungseinheit geben.
Das gesamte Programm darf null oder eine externe Definition jedes Bezeichners mit externer Verknüpfung haben.
Wenn ein Bezeichner mit externer Verknüpfung in einem Ausdruck verwendet wird, der kein
Nicht-VLA-,
(seit C99)
sizeof
,
_Alignof
(seit C11)
(bis C23)
,
alignof
(seit C23)
- oder
typeof
(seit C23)
Ausdruck ist, muss es genau eine externe Definition für diesen Bezeichner im gesamten Programm geben.
Hinweise
|
Inline-Definitionen in verschiedenen Übersetzungseinheiten unterliegen nicht den Einschränkungen der One Definition Rule. Siehe
|
(seit C99) |
Siehe Speicherdauer und Verknüpfung für die Bedeutung des Schlüsselworts extern bei Deklarationen im Dateigültigkeitsbereich
Siehe Definitionen für die Unterscheidung zwischen Deklarationen und Definitionen.
Vorläufige Definitionen wurden eingeführt, um verschiedene Prä-C89-Ansätze zur Vorwärtsdeklaration von Bezeichnern mit interner Verknüpfung zu standardisieren.
Referenzen
- C23-Standard (ISO/IEC 9899:2024):
-
- 6.9 Externe Definitionen (p: TBD)
- C17-Standard (ISO/IEC 9899:2018):
-
- 6.9 Externe Definitionen (S: 113-116)
- C11-Standard (ISO/IEC 9899:2011):
-
- 6.9 Externe Definitionen (S: 155-159)
- C99-Standard (ISO/IEC 9899:1999):
-
- 6.9 Externe Definitionen (S. 140-144)
- C89/C90 Standard (ISO/IEC 9899:1990):
-
- 3.7 EXTERNE DEFINITIONEN