extern int a;
int a = 1;
int main(void)
{
return 0;
}
これはUBですか?標準は 6.2.2/7 で言う
翻訳単位内で、同じ識別子が内部リンケージと外部リンケージの両方で表示される場合、動作は未定義です。
デフォルトのリンケージは extern
. 指定子は、extern
別の翻訳単位または同じ翻訳単位で定義および初期化される可能性があることを示します。宣言の相対的な配置はextern
重要ではありません。
C99 TC2 §6.9.2/1
オブジェクトの識別子の宣言にファイル スコープと初期化子がある場合、宣言は識別子の外部定義です。
次に例を示します。
int i1 = 1; // definition, external linkage
…
extern int i1; // refers to previous, whose linkage is external
これは完全に定義された動作です。これは、ヘッダーがインクルードされた後に前処理を行った後にコンパイラが取得するものです。
あなたの混乱は次のように思われます:
int a = 1;
内部リンケージはありません。ファイルスコープa
で外部リンケージがあります。static
指定子が追加された場合、内部リンケージがあります。
答えはイエスとノーです。
が同じ翻訳単位の他の場所で定義されている場合a
、はい、未定義の動作です。
a
がどこにも定義されていない場合は、 int a=1
; の外部定義と見なされますa
(同じファイルで定義されているにもかかわらず)。したがって、未定義ではありません。
はい、これは(ツールチェーンに依存する)動作につながると思います。なんで?
int a = ...;
. _ この行extern int a;
は、「a」へのすべての参照がリンカーによって解決されることをコンパイラーに伝えます。
これにより、コンパイラがこの矛盾を処理する方法が 2 つ残されます。 1. たまたま ('a' と呼ばれる可視シンボルが 1 つしかないため)、リンカは同じ翻訳単位の作成されたシンボル 'a' への参照をバインドします。2. コンパイラは extern ステートメントを無視し、このコンパイル単位の a に直接バインドします。
「内部」シンボルは static ( ) として宣言するstatic int a = ...;
必要があり、そうすれば UB を取得できると思います。