名稱空間
變體
操作

外部和暫定定義

來自 cppreference.com
< c‎ | language

翻譯單元的頂層(即經過預處理器處理後的原始檔和所有 #include),每個 C 程式都是一系列的宣告,這些宣告聲明瞭具有外部或內部連結的函式和物件。這些宣告被稱為外部宣告,因為它們出現在任何函式之外。

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
{
}

透過外部宣告宣告的物件具有靜態儲存期,因此不能使用 autoregister 說明符,除了 auto 可用於型別推斷外(C23 起)。由外部宣告引入的識別符號具有檔案作用域

目錄

[編輯] 暫定定義

暫定定義是沒有初始化器,並且沒有儲存類說明符或帶有說明符 static 的外部宣告。

暫定定義是可能充當或不充當定義的宣告。如果在同一翻譯單元中較早或較晚找到實際的外部定義,則暫定定義僅充當宣告。

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

如果同一翻譯單元中沒有定義,則暫定定義充當實際定義,該定義空初始化物件。

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;"

與不改變識別符號連結(如果之前的宣告已建立)的extern 宣告不同,暫定定義可能與同一識別符號的另一個宣告在連結上不一致。如果同一識別符號的兩個宣告在作用域內並且具有不同的連結,則行為未定義

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

具有內部連結的暫定定義必須具有完整型別。

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

[編輯] 單一定義規則

每個翻譯單元可以有零個或一個具有內部連結(一個 static 全域性)的每個識別符號的外部定義。

如果具有內部連結的識別符號用於除非變長陣列 (VLA),(C99 起) sizeof_Alignof(C11 起)(C23 止)alignof(C23 起)typeof(C23 起)之外的任何表示式中,則在該翻譯單元中必須有且僅有一個該識別符號的外部定義。

整個程式可以有零個或一個具有外部連結的每個識別符號的外部定義。

如果具有外部連結的識別符號用於除非變長陣列 (VLA),(C99 起) sizeof_Alignof(C11 起)(C23 止)alignof(C23 起)typeof(C23 起)之外的任何表示式中,則在整個程式中必須有且僅有一個該識別符號的外部定義。

[編輯] 注意

不同翻譯單元中的內聯定義不受單一定義規則的約束。有關行內函數定義的詳細資訊,請參閱inline

(C99 起)

有關檔案作用域宣告中關鍵字 extern 的含義,請參閱儲存期和連結

有關宣告和定義之間的區別,請參閱定義

暫定定義是為了標準化各種 C89 之前的前向宣告具有內部連結的識別符號的方法而發明的。

[編輯] 參考

  • C23 標準 (ISO/IEC 9899:2024)
  • 6.9 外部定義 (p: TBD)
  • C17 標準 (ISO/IEC 9899:2018)
  • 6.9 外部定義 (p: 113-116)
  • C11 標準 (ISO/IEC 9899:2011)
  • 6.9 外部定義 (p: 155-159)
  • C99 標準 (ISO/IEC 9899:1999)
  • 6.9 外部定義 (p: 140-144)
  • C89/C90 標準 (ISO/IEC 9899:1990)
  • 3.7 外部定義