2017-02-15 22 views
4

時警告或錯誤假設下面的代碼:GCC沒有定義一個局部變量多次

交流:

#include <stdio.h> 

int a; 
int func(); 

int main(int argc, char **argv) { 
a = 7; 
int a2 = func(); 
printf("a is %d, a2 is %d\n", a, a2); 
return 0; 
} 

和BC:

int a; 

int func() 
{ 
a = 9; 
return a; 
} 

g++ a.c b.c -Wall -O0編譯它產生鏈接錯誤,如預期。但是,在調用gcc a.c b.c -Wall -O0時,它不會產生警告並且不會出現錯誤!順便說一句,

輸出是a is 9, a2 is 9

gcc版本5.4.0 20160609(Ubuntu的5.4.0-6ubuntu1〜16.04.4)

爲什麼GCC允許這樣做? 我對這種行爲感到驚訝。如果你在聲明時初始化變量,那麼GCC也會失敗。

+0

嘗試在*相同*文件中定義兩次。你會感到驚訝。 http://en.cppreference.com/w/c/language/extern –

+0

複製直到鏈接器才顯示出來,並且由於沒有引用'a'的* external *實例,所以重複定義不被注意並被忽略。 – Mike

+0

這是本週早些時候由別人提出的問題([爲什麼這個程序沒有錯誤?](https://stackoverflow.com/questions/42215669/))。這被封閉爲[C99中的暫時定義和鏈接](https://stackoverflow.com/questions/1490693/)的副本。它已經在[如何使用'extern'在C源代碼文件之間共享變量?](https://stackoverflow.com/questions/1433204/) –

回答

5

g++ a.c b.c -Wall -O0一起編譯時,它會產生鏈接錯誤,如預期的那樣。但是,在調用gcc a.c b.c -Wall -O0時,它不會產生警告並且不會出現錯誤!

在你的代碼a暫定定義(這在當前翻譯單元的結束成爲定義),這是有效的。然而,有成爲一個完整的定義,另一個這樣的暫定定義來自另一個翻譯單元的b.c--這兩個單元都爲您的程序中的a提供外部定義。換句話說,a.cb.c可以獨立使用,但是當它們組合在一起編譯時(無論是直接編譯還是編譯爲單獨的模塊,然後通過鏈接它們來生成可執行文件),它們都是無效的。這是未定義的行爲

C11, 6.9/5

外部定義是一個外部聲明,這也是一個功能(比內聯定義其他)或對象的定義。如果在表達式中使用由外部鏈接聲明的標識符(除了作爲sizeof或_Alignof運算符的操作數的一部分,其結果是一個整數常量),則整個程序中的某處應該只有一個標識符的外部定義;否則,應該不超過一個.160

但是,這通常被gcc支持作爲擴展。這就是爲什麼當你調用gcc它編譯罰款爲C代碼。嚴格來說(標準方面),這是C中的無效代碼。當您調用g++將其編譯爲C++代碼時,它會失敗,因爲C++沒有試探性定義。它在C++中無效。因此,g++出錯。請參閱C++中的One Definition Rule