2016-10-29 3 views
0

私はexternキーワードでCと遊んでいましたが、この奇妙な動作に遭遇しました。 私は2つのファイルがあります:Cのconstの外部リンク

FILE1.Cを

#include<stdio.h> 
int main() 
{ 
    extern int a; 
    a=10; 
    printf("%d",a); 
    return 0; 
} 

file2.c

const int a=100; 

私は一緒にこれらのファイルをコンパイルすると、エラーまたは警告と私はそれらを実行し、出力はありません10となる。私はコンパイラがラインa=10;でエラーを報告するはずだと思っていました。私はグローバルのconst変数aの初期化を削除したファイルをコンパイルした場合、ある

const int a; 

にfile2.cの内容を変更した場合

また、まだエラーや警告はありませんが、私がそれらを実行すると、セグメンテーションフォルトが発生します。

この現象はなぜ発生しますか?定義されていない動作の下で分類されていますか?このコンパイラまたはマシンに依存していますか?

PS:これに関連する多くの質問がありましたが、C++用であるか、externについてのみ説明しています。

+0

これをチェックしてください:http://stackoverflow.com/a/28734780/4085019 – PseudoAj

+0

これはとても良い答えですが、私の質問には答えません。 – skrtbhtngr

答えて

0

これは未定義の動作ですが、コンパイラは警告しません。どうした?別のファイルに変数をどのように宣言するかはわかりません。

constと宣言された変数を変更しようとすると、未定義の動作になります。変数が読み取り専用メモリに格納されることは可能です(ただし必須ではありません)。

0

これはCコンパイラの動作として知られています。これは、強力なコンパイル時の型チェックが強制されるCとC++の違いの1つです。 セグメンテーション違反は、リンカーがconst値を読み取り専用のelfセグメントに置き、このメモリーアドレスへの書き込みが実行時(セグメンテーション)エラーであるため、値をconstに割り当てるときに発生します。 コンパイル時にコンパイラは "externs"をチェックせず、Cリンカは型をテストしません。それゆえコンパイル/リンケージを渡します。

+0

Yanir、「強力なコンパイル時の型チェックが強制されるCとC++の違いの1つです。あなたは、C++コンパイラがこの問題を抱えていると言いたいのですか?ファイルは異なるので、オブジェクトファイルに別々にコンパイルされる可能性があります。 –

+0

@JayRajput C++コンパイラはこれを捕まえていませんでしたが、リンカが持っていました。 – user4581301

+1

@ user4581301、オンラインで混乱している情報があるようです。たとえば、このstackoverflowの記事では、リンカーがextern変数の型チェックを行っていないことを示唆しています。 http://stackoverflow.com/questions/28090854/is-there-any-type-checking-in-c-or-c-linkers。リンカがextern変数の型チェックを行っていることを証明するソースがありますか?私はそれについてもっと理解したいと思います。 –

1

コンパイルとリンクは2つの異なるフェーズです。コンパイル時に、個々のファイルがオブジェクトファイルにコンパイルされています。コンパイラは、file1.cとfile2.cの両方が内部的に一貫していることを確認します。リンクフェーズ中、リンカは変数aのすべてのオカレンスを同じメモリ位置にポイントするだけです。これは、コンパイルやリンカーのエラーが表示されない理由です。

上記の問題を避けるには、externをヘッダーファイルに置き、そのヘッダーファイルを別のCファイルにインクルードすることをお勧めします。この方法でコンパイラは、ヘッダとCファイルの間の矛盾をキャッチすることができます

次のstackoverflowは、extern変数の型チェックを行うことができないリンカについても説明します。

Is there any type checking in C or C++ linkers?

あなたがにextern int型のテストを宣言するので、もし同様に、グローバル変数(やクラスなどの静的メンバ)のタイプは、リンカによって確認されていません。フロートテストを定義します。別の場合には、あなたは悪い結果を得るでしょう。

0

プログラムでは、診断が不要で、定義されていない動作が発生します(const int aに初期化子があるかどうかにかかわらず)。 C11の関連テキストは6.2.7/2です。

同じオブジェクトまたは関数を参照するすべての宣言は互換性のある型を持ちます。それ以外の場合、動作は未定義です。

また6.2.2/2:

プログラム全体を構成する翻訳単位とライブラリのセットでは、外部結合を持つ特定の識別子の各宣言が同じオブジェクトまたは関数を表します。

Cでは、const int a = 100;は、aが外部リンケージを有することを意味する。したがって、extern int a;と同じオブジェクトを示します。ただし、これらの2つの宣言には互換性のない型があります(intconst intと互換性がありません。「互換型」の定義については6.7.2を参照してください)。

関連する問題