現在、小さな C プログラムのコンパイル/リンク中に GCC からエラーが発生しないのはなぜか疑問に思っています。
version.h
次の文字列で宣言しました:
const char* const VERSION;
version.c
変数の初期化を設定しました:
const char* const VERSION = "0.8 rev 213";
問題ありません。プログラムの残りの部分で文字列を使用できます。
c ファイルが見つからない場合、コンパイル/リンク中にエラーは発生しませんが、プログラムが変数にアクセスしようとすると、SIGSEGV (当然) で失敗します。
変数を設定する私の方法はVERSION
正しいでしょうか、それとももっと良い方法があるのでしょうか? あるいは、コンパイル/リンク中にエラーが発生する可能性はありますか?
ベストアンサー1
あなたが持っている定義されたヘッダー内の変数を(単に宣言するのではなく)
このヘッダーを複数のソースファイルからインクルードした場合、動作は次のようになります。未定義以下は標準からの関連する引用です。
J.2 未定義の動作
…
外部リンケージを持つ識別子が使用されていますが、プログラム内にその識別子の外部定義が 1 つだけ存在しないか、または識別子が使用されず、その識別子の外部定義が複数存在します。
…
ここではGCC特有の(実際には多くのコンパイラに共通だが、それでも非標準)動作、つまり重複したコードのマージに依存しています。仮のデータ定義。および-fcommon
GCC-fno-common
コンパイル フラグのヘルプを参照してください。すべてのコンパイラがこのように動作するわけではありません。歴史的に、これはリンカーの一般的な動作です。これは、C が登場する前の Fortran の動作だったためです。
この言語拡張を前提とすると、定義の 1 つ (明示的な初期化子を持つもの) は、変数を初期化して文字列リテラルを指します。ただし、この定義を省略すると、ゼロで初期化されたままになります。つまり、定数の null ポインターになります。あまり役に立ちません。
簡単に言うと、絶対にそんなことはしないでください。ヘッダーでグローバル変数を宣言(定義ではなく)するには、 を使用しますextern
。そうして、他の場所で定義を省略しようとすると、おそらくリンカー エラーが発生します (標準ではこの違反の診断は要求されていませんが、既知の実装はすべて 1 つを生成します)。