C與C 對於全域性變數的不同處理之處

2021-12-30 00:01:32 字數 1606 閱讀 4299

下面看看我犯的錯誤:

當時寫了乙個類似於下面的列舉:

#ifndef test_enum_h_

#define test_enum_h_

enum 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()

檔案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段的不同:

在這篇文章中,我解釋了為什麼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++的鏈結機制有關。目前我並不清楚原因,有了解的朋友請賜教。謝謝。

摘自 十分愛的部落格

C 靜態全域性變數與普通全域性變數

一 儲存區域 1 棧 由編譯器在需要的時候分配,在不需要的時候自動清除的變數的儲存區域。通常儲存區域性變數,函式引數。2 堆 由new分配的記憶體塊,需要手動釋放。如果程式設計師沒有手動釋放,在程式執行結束後,作業系統自動 3 自由儲存區 由malloc等分配的記憶體塊,與堆相似,用free來釋放。...

c 全域性變數 靜態全域性變數

全域性變數是靜態儲存方式,靜態全域性變數也是靜態儲存方式,這兩者在儲存方式上並無不同。區別 雖在於非靜態全域性變數的作用域是整個源程式,當乙個源程式由多個原始檔組成時,靜態全域性變數在各個原始檔中都是有效的。靜態區域性變數則限制了其作用域,只在定義該變數的原始檔內有效,在同一源程式的其它原始檔中不能...

C 全域性變數

c 工程有以下幾個檔案 標頭檔案 a.h,b.h 相應的cpp檔案 a.cpp 包含a.h b.cpp 包含b.h 以及其他一些相關的.h,cpp檔案。a中有類a,b中有類b。現在需要在b.cpp中使用a.cpp 類a中的乙個變數,且希望其是隨著a.cpp 類a的呼叫更新的值。可按如下操作 在a.h...