名前空間
変種

外部定義と仮定義

提供: cppreference.com

翻訳単位 (つまり、すべての #include を含む、プリプロセッサの後のソースファイル) のトップレベルでは、 C のプログラムは宣言の並びであり、それらの宣言は外部リンケージを持つ関数およびオブジェクトを宣言します。 それらの宣言はあらゆる関数の外側に現れるため、外部宣言と言います。

extern int n; // 外部リンケージを持つ外部宣言。
int b = 1;    // 外部リンケージを持つ外部定義。
static const char *c = "abc"; // 内部リンケージを持つ外部定義。
int f(void) {  // 外部リンケージを持つ外部定義。
    int a = 1; // 外部でない。
    return b; 
}
static void x(void) { // 内部リンケージを持つ外部定義。
}

外部宣言を用いて宣言されたオブジェクトは静的記憶域期間を持ち、そのため auto または register 指定子は使用できません。 外部宣言によって導入された識別子はファイルスコープを持ちます。

仮定義

仮定義は、初期化子を持たず、記憶域クラス指定子を持たないか static 指定子を持つ、外部宣言です。

仮定義は定義として振る舞う場合もそうでない場合もある宣言です。 同じ翻訳単位内で以前または以後に実際の外部定義がある場合は、仮定義は宣言として振る舞います。

int i1 = 1;     // 定義。 外部リンケージ。
int i1;         // 仮定義。 i1 が定義されているため、宣言として振る舞います。
extern int i1;  // 宣言。 以前の定義を参照します。

extern int i2 = 3; // 定義。 外部リンケージ。
int i2;            // 仮定義。 i2 が定義されているため、宣言として振る舞います。
extern int i2;     // 宣言。 外部リンケージの定義を参照します。

同じ翻訳単位内に定義がない場合は、仮定義は初期化子 = 0 (配列、構造体、共用体型の場合は = {0}) を持つ実定義として振る舞います。

int i3;        // 仮定義。 外部リンケージ。
int i3;        // 仮定義。 外部リンケージ。
extern int i3; // 宣言。 外部リンケージ。
// この翻訳単位では、 i3 は「int i3 = 0;」であるかのように定義されます。

以前の宣言 (もしあれば) が確立した識別子のリンケージを変更しない extern 宣言と異なり、仮定義は同じ識別子の別の宣言とリンケージについて合意しない場合があります。 同じ識別子の2つの宣言が同じスコープ内であり異なるリンケージを持つ場合、動作は未定義です。

static int i4 = 2; // 定義。 内部リンケージ。
int i4;            // 未定義動作。 上の行とリンケージが異なります。
extern int i4;     // 宣言。 内部リンケージの定義を参照します。

static int i5; // 仮定義。 内部リンケージ。
int i5;        // 未定義動作。 上の行とリンケージが異なります。
extern int i5; // 宣言。 内部リンケージの定義を参照します。

内部リンケージを持つ仮定義は完全型でなければなりません。

static int i[]; // エラー。 static 仮定義で不完全型が使用されました。
int i[]; // OK。 int i[1] = {0}; と同等です (翻訳単位内で別の宣言がなければ)。

単一定義規則

各翻訳単位は内部リンケージを持つ (static グローバルな) すべての識別子の定義を0個または1個持つことができます。

内部リンケージを持つ識別子が VLA でない (C99以上) sizeof、またはalignof (C11以上) 以外の何らかの式で使用された場合、その翻訳単位内でその識別子のための外部定義が1個 (だけ) 存在しなければなりません。

プログラム全体で外部リンケージを持つすべての識別子 (inline 関数は除きます) (C99以上)の外部定義を0個または1個持つことができます。

外部リンケージを持つ識別子が VLA でない (C99以上) sizeof、または alignof (C11以上) 以外の何らかの式で使用された場合、プログラム全体のどこかにその識別子のための外部定義が1個 (だけ) 存在しなければなりません。

ノート

インライン関数の定義の詳細については inline を参照してください。

ファイルスコープの宣言におけるキーワード extern の意味については記憶域期間とリンケージを参照してください。

宣言と定義の違いについては定義を参照してください。

仮定義は内部リンケージを持つ識別子を前方宣言するための C89 より前の様々な手法を標準化するために発明されました。

参考文献

  • C11 standard (ISO/IEC 9899:2011):
  • 6.9 External definitions (p: 155-159)
  • C99 standard (ISO/IEC 9899:1999):
  • 6.9 External definitions (p: 140-144)
  • C89/C90 standard (ISO/IEC 9899:1990):
  • 3.7 EXTERNAL DEFINITIONS