Cはそれが未定義の振る舞いであると言います。
(C99、6.9p5)「外部リンケージで宣言された識別子が式で使用される場合(結果が整数定数であるsizeof演算子のオペランドの一部として以外)、プログラム全体のどこかに、外部が1つだけ存在する必要があります。識別子の定義。それ以外の場合は、1つしか存在しないものとします。」
未定義の動作であるということは、リンカが複数の外部オブジェクト定義の存在下でリンクプロセスを中止できることを意味します。
現在、リンカーは優れており(または悪であり、選択できます)、通常、複数の外部オブジェクト定義を処理するためのデフォルトの拡張機能があり、場合によっては失敗しません。
binutilsを使用gcc
しld
ている場合、2つのオブジェクトが明示的に初期化されていると、エラーが発生します。たとえばint x = 0;
、最初の翻訳単位にとがありdouble x = 0.0;
ます。
それ以外の場合、外部オブジェクトの1つが明示的に初期化されていない場合(この例の状況)gcc
、2つのオブジェクトがサイレントに1つのシンボルに結合されます。オプションを渡すことで、リンカーに警告を報告するように依頼することもできます--warn-common
。
たとえば、モジュールをリンクする場合:
gcc -Wl,--warn-common module1.o module2.o
--fatal-warnings
リンクプロセスを中止するには、オプション( )を使用して、すべての警告をエラーとして処理するようにリンカに要求できます-Wl,--fatal-warnings,--warn-common
。
リンクプロセスを中止する別の方法は、 @ teppic-fno-common
の回答で説明されているように、コンパイラオプションを使用することです。外部オブジェクトがコンパイル時に共通シンボルタイプを取得することを禁止します。モジュールとリンクの両方に対してこれを行うと、複数定義リンカーエラーも発生します。-fno-common
gcc -Wall -fno-common -c module1.c module2.c
gcc module1.o module2.o