C言語で変数を2つのファイルで2回定義できないのはなぜですか?質問する

C言語で変数を2つのファイルで2回定義できないのはなぜですか?質問する

なぜ私は整数a;2 つの C ファイルにあります。両方を組み合わせて実行可能にするつもりです。経験上、できないことはわかっていますが、標準 C99 のどこにこれが書かれているのかを見つけて、理解を深めたいと思います。

私はISO C99規格を読んでいますhttp://www.open-std.org/jtc1/sc22/wg...docs/n1256.pdf42ページにはこう書いてあります。

6.2.2 識別子のリンク

1 異なるスコープ内または同じスコープ内で複数回宣言された識別子は、リンケージと呼ばれるプロセスによって同じオブジェクトまたは関数を参照するようにすることができます。リンケージには、外部リンケージ、内部リンケージ、およびなしリンケージの 3 種類があります。

2 プログラム全体を構成する翻訳単位とライブラリのセットでは、外部リンケージを持つ特定の識別子の各宣言は同じオブジェクトまたは関数を表します。 1 つの翻訳単位内では、内部リンケージを持つ識別子の各宣言は同じオブジェクトまたは関数を表します。 リンケージを持たない識別子の各宣言は、一意のエンティティを表します。

3 オブジェクトまたは関数のファイル スコープ識別子の宣言にストレージ クラス指定子 static が含まれている場合、その識別子には内部リンケージがあります。

4 ストレージ クラス指定子 extern を使用して宣言された識別子が、その識別子の以前の宣言が可視であるスコープ内で、以前の宣言で内部または外部のリンケージが指定されている場合、後の宣言での識別子のリンケージは、以前の宣言で指定されたリンケージと同じになります。以前の宣言が可視でない場合、または以前の宣言でリンケージが指定されていない場合、識別子には外部リンケージがあります。

5 関数の識別子の宣言にストレージ クラス指定子がない場合、そのリンケージはストレージ クラス指定子 extern を使用して宣言された場合とまったく同じように決定されます。オブジェクトの識別子の宣言にファイル スコープがあり、ストレージ クラス指定子がない場合、そのリンケージは外部です。

これを読んでみると、例えば次のように変数を宣言すると、整数a;2 つのソース ファイルにあります。ルール 5 および 4 に従って、両方とも外部リンケージを持ちます。ルール 2 に従って、両方とも同じオブジェクトを参照する必要があります。では、なぜコンパイラーは問題を作成するのでしょうか。標準のどこに、2 つのソース ファイルでこのように宣言することはできないため、コンパイル エラーが発生すると示唆されていますか。まず、標準のどこに、int a は定義であると書かれており、次に、定義の 2 つのインスタンスは受け入れられないと書かれています。経験から、これは許可されていないことはわかっていますが、標準でこれを見つけて理解を深めることができれば、非常に役立ちます。

標準からの次の抜粋を組み合わせると、このルールに該当しますか? それとも、その接着剤を見逃したのでしょうか?:

宣言は、識別子のセットの解釈と属性を指定します。識別子の定義は、その識別子の宣言であり、次のようになります。 - オブジェクトの場合、そのオブジェクト用にストレージが予約されます。 - 関数の場合、関数本体が含まれます。 - 列挙定数または typedef 名の場合、識別子の (唯一の) 宣言です。

5.1.1.1 で説明したように、前処理後のプログラム テキストの単位は、一連の外部宣言で構成される翻訳単位です。これらは、関数の外部に出現するため (したがってファイル スコープを持つため)、「外部」と呼ばれます。6.7 で説明したように、識別子で指定されたオブジェクトまたは関数用にストレージを予約する宣言は、定義です。

外部定義は、関数 (インライン定義以外) またはオブジェクトの定義でもある外部宣言です。外部リンケージで宣言された識別子が式で使用される場合 (結果が整数定数である sizeof 演算子のオペランドの一部として使用される場合を除く)、プログラム全体のどこかに、その識別子の外部定義が 1 つだけ存在する必要があります。それ以外の場合は、1 つしか存在できません。

ありがとう。

ベストアンサー1

6.9.2/2 が必要だと思います:

初期化子なしでファイルスコープを持つオブジェクトの識別子の宣言、およびストレージクラス指定子なしまたはストレージクラス指定子付きの宣言はstatic暫定的な定義翻訳単位に識別子の暫定定義が 1 つ以上含まれており、翻訳単位にその識別子の外部定義が含まれていない場合、動作は、翻訳単位にその識別子のファイル スコープ宣言 (翻訳単位の終了時点の複合型、初期化子が 0 である) が含まれている場合とまったく同じになります。

6.9/5:

アン外部定義関数(インライン定義以外)またはオブジェクトの定義でもある外部宣言です。外部リンケージで宣言された識別子が式内で使用される場合(sizeof結果が整数定数となる演算子のオペランドの一部として使用される場合を除く)、プログラム全体のどこかにその識別子の外部定義が 1 つだけ存在する必要があります。それ以外の場合は、1 つしか存在できません。

int a;基本的には、暫定的な定義1 つの翻訳単位に複数の暫定定義を含めることができますが、その効果は 1 つの非暫定外部定義 ( などint a = 0;) と同じになります。プログラム内に外部リンケージを持つオブジェクトの定義を複数含めることは、6.9/5 の違反です。

最大でも 1 つのみ初期化され、定義が一致する限り、オブジェクトの複数の外部定義を許可することは「共通拡張」であることに注意してください (J.5.11 を参照)。

おすすめ記事