@mscは、この動作の背後にあるルールを適切に紹介します。
グローバル変数を複数回宣言すると、コンパイラは警告を出力しません。
Cには、オブジェクト用の3種類のグローバル宣言がありますstatic
。
- 定義ではない宣言—
extern int a;
- 定義でもある宣言-
int a = 3;
またはextern int a = 3;
- 暫定的な定義—
int a;
タイプ1および3の複数の宣言が許可されていますが、最大1つの(タイプ2)定義が許可されています。
この動作の説明は何ですか?
これらのルールの動機についても質問している場合は、個別のコンパイルのサポートです。(翻訳単位を参照)。
プログラムを個別にコンパイルされた複数のファイルに分割するには、いくつかの機能が必要です。つまり、(a)必ずしも定義せずに宣言できること、(b)前方に宣言することです。
1つの翻訳単位内で、別の翻訳単位のグローバル関数とデータを参照できる必要があります。また、ここでは、欠落している定義や誤った定義の重複を発見するためのエラーチェックも必要です。
同じ翻訳単位でグローバルを宣言し、後で定義する場合があります。これは、何らかの理由で前方宣言が必要な場合、または明示的な定義も提供する1つの変換単位内で(宣言を提供する)共通ヘッダーファイルを使用する場合に発生する可能性があります。
Cでの個別のコンパイルはグローバル関数とデータをリンクすることによって適用されるため、これらの機能はグローバルレベルで必要ですが、ローカルレベルでは必要ありません。
@mscが指摘しているように、ローカル変数はリンケージがないため、これらはローカル変数には必要ありません。
Cは(他の多くの言語と同様に)、ローカル変数のリンケージを提供しません。これは、言語が複数の個別の翻訳単位にわたる単一の関数をサポートしようとしないためです。
(もちろん、関数を複数のソースファイルにまたがることはできますが、複数の翻訳単位にはできません。)
仮の定義は宣言と同じように機能し、複数の翻訳単位で許可されます(他の宣言とうまく結合します)。ただし、プログラム全体に識別子の(一時的でない)定義がない場合、(1つの識別子の)複数の翻訳単位にわたる(1つ以上の)一時的な定義のセットは、初期化子が存在するオブジェクトの定義として使用されます。ゼロ。
これは、適切なサイズと配置でこれらを.BSSセクションに配置することで実装できます。リンカは、それらを実際の定義に一致する場合は一致させるか、またはそれらを互いに一致させて、BSSのスペースをゼロに設定します。
個別のコンパイルの概念は、暫定的な定義の機能がなくても完全にサポートできます—暫定的な定義は主に歴史的な理由で存在すると思います。(私がそれらが役に立たないと言っているわけではありません。もしその言語が今日作成されたとしても、これは不必要と見なされ、したがって提供されないかもしれません。)