Namespaces
Variants

External and tentative definitions

From cppreference.net

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 inline für Details zu Inline-Funktionsdefinitionen.

(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