下面看看我犯的錯誤:
當時寫了一個類似於下面的枚舉:
#ifndef TEST_ENUM_H_
#define TEST_ENUM_H_
enum {
TEST_FLAG1_E,
TEST_FLAG2_E,
TEST_FLAG_NR
} TEST_E;
#endif
當時在enum關鍵字前面遺漏了“typedef”。我一般習慣於使用typedef,這樣可以直接使用TEST_E而不是enum TEST_E。
該頭文件會被其它源文件引用。由於在代碼中,沒有需要定義枚舉變量的地方,只是使用枚舉的值,所以當時沒有發現遺漏“typedef”。編譯也沒有任何問題。
但是當天的build卻沒有通過。錯誤信息顯示定義了重復的TEST_E,因此編譯失敗。由於與美國的時差問題,這個錯誤由美國的一同事修改了。他陳述的錯誤原因是:這樣的枚舉聲明對於C來說,是沒有問題的。——我們的核心代碼都是C編寫的。
但是對於C++,會認為不是聲明而是定義,定義了一個TEST_E變量。結果導致重復定義了該變量。——有一部分web功能代碼是使用C++編寫的。
當我早上看到他的說明時,首先要對break build表示歉意;第二也鄙視了一下該產品的makefile——我剛剛加入這個產品組。這樣的makefile,為了檢查checkin,我不得不先make clean才能保證所有的代碼被編譯。這樣花費的時間太多了。第三,我才想起web的這部分功能是使用C++的。第四,寒一下自己,居然漏寫了typedef;第五,也有些好奇C++的編譯為什麼出錯。
但是當我看到他的陳述時,我知道他肯定錯了。對於C和C++來說,枚舉enum的區別不會這麼大。對於上面那個枚舉類型定義,由於遺漏了typedef,所以這裡的TEST_E無論是C還是C++來說,都會把TEST_E當作一個枚舉變量處理,也就是一個全局變量。那麼引起問題的原因是因為C和C++對於沒有初始值的全局變量的處理不同——真拗口,而最後的編譯鏈接行為不同。
看下面的簡單示例:
文件test1.c
int a;
int main()
{
return 0;
}
文件tes2.c
int a;
編譯
[fgao@fgao-vm-fc13 test]$ gcc -g -Wall test1.c test2.c
[fgao@fgao-vm-fc13 test]$
編譯沒有任何的warning和error。對於沒有初始值的全局變量,其為弱符號。對於多個弱符號定義,在C的鏈接階段不會有任何問題。大家可以參見我這篇文章通過未初始化全局變量,研究BSS段和COMMON段的不同:http://www.BkJia.com/kf/201202/118030.html
在這篇文章中,我解釋了為什麼C允許多個弱符號存在
下面將其視為C++代碼,使用g++編譯:
[fgao@fgao-vm-fc13 test]$ g++ -g -Wall test1.c test2.c
/tmp/ccQdTwRi.o:(。bss+0x0):multiple definition of `a'
/tmp/cc7SOWD1.o:/home/fgao/works/test/test1.c:4: first defined here
collect2: ld returned 1 exit status
同樣是沒有初始值的全局變量,在C++的鏈接階段就會報錯。對於C++為什麼報錯,這肯定是由於C++的鏈接機制有關。目前我並不清楚原因,有了解的朋友請賜教。謝謝。
摘自 十分愛的博客