1. 程式人生 > >能不能在標頭檔案中定義全域性變數?

能不能在標頭檔案中定義全域性變數?

首先,這是一篇科普文,所以 比較雜,我儘量寫清楚一些。

1、ANSI C標準是什麼?GNU又是什麼?ld是什麼?

ANSI C是C語言的標準規範,是國際標準化組織制定的國際標準。

雖然 ANSI C規範了C語言的實現,但是在實際情況中,各家C語言提供商都會根據平臺的不同情況對ANSI C進行一定的擴充套件。因此可以將現實中C語言實現看作是ANSI C的一個超集。比較有代表性的例子是linux的gcc編譯器。由於該編譯器對ANSI C進行了非常多的擴充套件,linux核心原始碼基本上只能在gcc上面 進行編譯,希望通過其他的編譯器來編譯linux核心幾乎是不可能的。

GNU計劃,又稱革奴計劃。它的目標是建立一套完全自由的作業系統。1990年,GNU計劃已經開發出的軟體包括了一個功能強大的文字編輯器Emacs  。GCC(GNU Compiler Collection,GNU編譯器集合),是一套由 GNU 開發的程式語言編譯器。

GNU工具鏈包括了構建linux開發環境所需的編譯、連結、除錯、軟體工程等工具。GCC(編譯器)、Gdb(偵錯程式)、make(軟體等工程工具)。GCC下包括gcc,g++工具。GNU binutils是一組二進位制工具程式集,是輔助GCC的主要軟體,包括我們熟悉的as(GNU彙編器),ar(建立、修改、提取歸檔檔案,歸檔檔案是包含多個檔案內容的一個大檔案)、ld(聯結器,把目標檔案和歸檔檔案結合在一起),我們在寫程式的時候,有時候報錯:[Error] ld returned 1 exit status,這就是程式在連結的時候出錯了。

2、C語言可以在不同的原始檔中定義相同名字的全域性變數嗎?

不使用static的時候,兩個不同的原始檔都可以正常編譯,但會出現連結錯誤,原因是有兩個地方存在相同的變數,導致編譯器無法識別應該使用哪一個。

關於全域性變數的幾點說明:

①預設情況下,C語言中的全域性變數和函式的作用域僅限於定義和宣告這個函式或變數的內部,如果需要從這個C檔案之外訪問這些函式或者全域性變數就需要使用 extern關鍵字進行宣告,這是因為C編譯器是以C檔案為單位進行編譯的,如果這個C檔案中引用了其他檔案中定義的函式或者變數,編譯器將無法找到這個函式或者變數的定義,從而給出該函式或者變數未定義的錯誤資訊。

②static關鍵字用於全域性變數的宣告時,作用類似於函式的情況,這個全域性變數的作用域將侷限在宣告該變數的c檔案內部,這個c檔案之外的程式碼將無法訪問這個變數。編譯的時候將會出現類似undeference to "xxx"的報錯,它是找不到xxx的,因為使用static相當於進行了檔案隔離。

3、那麼再引申另一個問題,能不能在標頭檔案中定義全域性變數?

因為變數只能被定義一次,包含了標頭檔案的原始檔,都將會定義同樣的全域性變數,造成衝突,所以,標頭檔案中不能定義全域性變數。還有網友從節省記憶體的角度來分析,還得到了很多贊,我覺得解釋的不對啊!詳見c語言 中 為什麼不將全域性變數的定義放在標頭檔案中

4、本部落格的導火索,

就是因為在一個大的工程中,需要增加一個全域性變數,一開始我是加在了某一個頭檔案中,然後報重複定義的錯誤,很顯然,就是因為第2點中說的,由於這個標頭檔案被多個原始檔include,雖然在編譯階段可能能通過,但是在連結的時候就會出現重複定義的錯誤。

解決辦法:

①處於儘可能的改動較少的檔案的檔案的原則,自己寫一個頭問價,檔案內容就一條:全域性變數的定義。這樣的話,在需要使用的位置通過include這個標頭檔案就可以了。但是,如果有多個原始檔需要使用使用這個變數的話,這種情況也會發生重複定義的錯誤,因為include的過程就是複製的過程,那麼很顯然了,這個標頭檔案被拷貝到了多個原始檔中,連結時肯定會出現重複定義的錯誤啊。

而且,假設只有一個原始檔需要這個全域性變數,那麼直接在這個原始檔中定義全域性變數就好了啊!還定義什麼鬼標頭檔案哦!

②假設工程中的多個原始檔需要這個全域性變數,那麼你就任找一個原始檔,把這個全域性變數定義到這個原始檔中,然後新建一個頭檔案,在裡面進行extern 這個變數的宣告,最後在需要使用這個全域性變數的原始檔中include你新建的標頭檔案就OK了。

參考:

[1] 嵌入式系統高階C語言程式設計,凌明編著,第一章概述