Namensräume
Varianten
Aktionen

Externe und tentative Definitionen

Von cppreference.com
< c‎ | Sprache

Auf der obersten Ebene einer Übersetzungseinheit (d.h. einer Quelldatei mit allen #include nach dem Präprozessor) ist jedes C-Programm eine Abfolge von Deklarationen, die Funktionen und Objekte mit externer oder interner Bindung deklarieren. Diese Deklarationen sind als externe Deklarationen bekannt, da sie außerhalb jeder Funktion erscheinen.

extern int n; // external declaration with external linkage
int b = 1;    // external definition with external linkage
static const char *c = "abc"; // external definition with internal linkage
 
int f(void)    // external definition with external linkage
{
    int a = 1; // non-external
    return b;
}
 
static void x(void) // external definition with internal linkage
{
}

Objekte, die mit einer externen Deklaration deklariert werden, haben eine statische Speicherdauer und können daher keine auto- oder register-Spezifizierer verwenden außer dass auto zur Typinferenz verwendet werden kann(seit C23). Die durch externe Deklarationen eingeführten Bezeichner haben einen Dateibereich.

Inhalt

[bearbeiten] Tentative Definitionen

Eine tentative Definition ist eine externe Deklaration ohne Initialisierer und entweder ohne einen Speicherklassenspezifizierer oder mit dem Spezifizierer static.

Eine tentative Definition ist eine Deklaration, die als Definition fungieren kann oder auch nicht. Wenn eine tatsächliche externe Definition früher oder später in derselben Übersetzungseinheit gefunden wird, wirkt die tentative Definition lediglich als Deklaration.

int i1 = 1;     // definition, external linkage
int i1;         // tentative definition, acts as declaration because i1 is defined
extern int i1;  // declaration, refers to the earlier definition
 
extern int i2 = 3; // definition, external linkage
int i2;            // tentative definition, acts as declaration because i2 is defined
extern int i2;     // declaration, refers to the external linkage definition

Wenn keine Definitionen in derselben Übersetzungseinheit vorhanden sind, wirkt die tentative Definition als tatsächliche Definition, die das Objekt leer initialisiert.

int i3;        // tentative definition, external linkage
int i3;        // tentative definition, external linkage
extern int i3; // declaration, external linkage
// in this translation unit, i3 is defined as if by "int i3 = 0;"

Im Gegensatz zu den extern-Deklarationen, die die Bindung eines Bezeichners nicht ändern, wenn eine vorherige Deklaration ihn etabliert hat, können tentative Definitionen in der Bindung von einer anderen Deklaration desselben Bezeichners abweichen. Wenn zwei Deklarationen für denselben Bezeichner im Geltungsbereich liegen und unterschiedliche Bindungen haben, ist das Verhalten undefiniert.

static int i4 = 2; // definition, internal linkage
int i4;            // Undefined behavior: linkage disagreement with previous line
extern int i4;     // declaration, refers to the internal linkage definition
 
static int i5; // tentative definition, internal linkage
int i5;        // Undefined behavior: linkage disagreement with previous line
extern int i5; // refers to previous, whose linkage is internal

Eine tentative Definition mit interner Bindung muss einen vollständigen Typ haben.

static int i[]; // Error, incomplete type in a static tentative definition
int i[]; // OK, equivalent to int i[1] = {0}; unless redeclared later in this file

[bearbeiten] Eine-Definition-Regel

Jede Übersetzungseinheit darf null oder eine externe Definition jedes Bezeichners mit interner Bindung (eine static globale Variable) haben.

Wenn ein Bezeichner mit interner Bindung in einem anderen Ausdruck als einem nicht-VLA,(seit C99) sizeof, _Alignof(seit C11)(bis C23), alignof(seit C23), oder typeof(seit C23) verwendet wird, 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 Bindung haben.

Wenn ein Bezeichner mit externer Bindung in einem anderen Ausdruck als einem nicht-VLA,(seit C99) sizeof, _Alignof(seit C11)(bis C23), alignof(seit C23), oder typeof(seit C23) verwendet wird, muss es genau eine externe Definition für diesen Bezeichner irgendwo im gesamten Programm geben.

[bearbeiten] Hinweise

Inline-Definitionen in verschiedenen Übersetzungseinheiten unterliegen nicht der Eine-Definition-Regel. Siehe inline für Details zu Inline-Funktionsdefinitionen.

(seit C99)

Siehe Speicherdauer und Bindung für die Bedeutung des Schlüsselworts extern bei Deklarationen auf Dateiebene.

Siehe Definitionen für die Unterscheidung zwischen Deklarationen und Definitionen.

Tentative Definitionen wurden erfunden, um verschiedene Ansätze vor C89 zur Vorwärtsdeklaration von Bezeichnern mit interner Bindung zu standardisieren.

[bearbeiten] Referenzen

  • C23-Standard (ISO/IEC 9899:2024)
  • 6.9 Externe Definitionen (S. 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