2017-01-12 10 views
3

次の2つのコードは、Test1.cとTest2.cの2つのファイルに分かれています。どんなファイルでもexternキーワードを使用していません。 GCCを使用してこのコードをコンパイルなぜ、externが使われなくても、GCCは2つのファイルをコンパイルしてリンクするのですか?

//Test1.c 
#include <stdio.h> 

int a = 1; 
int main() 
{ 
    printf("test1 - a val = %d\n",a); 
    fn(); 
    printf("After Return : %d",a); 
} 

//Test2.c 
#include <stdio.h> 

int a; 
int fn() 
{ 
    printf("test2 - a val = %d\n",a); 
    a++; 
} 

I:これは以下の出力を生成

gcc Test1.c Test2.c 

test1 - a val = 1 
test2 - a val = 1 

Iは、両方のコードに可変aのアドレスを印刷しようとしました。アドレスも同じです。

は、今、私が質問に次き:

  1. gccは自動的externが使用されていない場合でも、コンパイルとリンクしません?ここでは明らかにgccが内部的にこの2つのファイルをまとめています。
  2. この動作は/なしでexternキーワードはコンパイラに依存しますか?
+0

厳密に準拠していません。これは、標準の附属書Jに記載されている「共通の拡張子」です。 [C言語でソースファイル間で変数を共有するために 'extern'を使うにはどうすればいいですか?]のセクション 'グローバル変数を定義するには良い方法ではありません'を参照してください。(http://stackoverflow.com/questions/1433204/) –

+0

'-fno-common'オプションです。 –

+0

@JonathanLefflerこれはどのようにその質問と重複することができますか?私の質問はgccコンパイラでexternの動作に関するものでした。 –

答えて

3

このコードは診断不要の未定義の動作です。外部リンケージで宣言識別子はsizeofまたは_Alignofのオペランドの一部として以外の(式で使用される場合

Test1.cTest2.c両方がC11 6.9/5に違反外部結合とオブジェクトaを定義します演算子が整数定数である演算子)、プログラム全体のどこか識別子の外部定義はちょうどです。さもなければ、1つしかない。

注:「外部定義」とは、ファイルスコープでの定義を意味します。 (C11 6.9/4,6.9/5)。他のコメント/回答は、「外部定義」と「外部リンケージを持つオブジェクトの定義」または「externキーワードを持つ定義」と混同しています。ファイルスコープのstatic int x = 5;は外部定義です。


コメントでJonathan Lefflerが述べたように、この特定の結果は意図的なGCC拡張である可能性があります。 C11附属書J.5.11「共通拡張」から:

キーワードexternを明示的に使用してもしなくても、オブジェクトの識別子の複数の外部定義が存在することがあります。定義が一致しない場合、または複数の定義が初期化された場合の動作は未定義です。

gccがこの拡張機能を実装すると、観察した動作が説明されます。恐らく、仮の定義のために生成された暗黙的な初期化子を数えないという点で、 "複数のものが初期化されている"と思われる。

関連する問題