C語言關鍵字學習(1)----- extern

序言:

       如果C語言是程序員手下的一支精銳之師,那麼基本語法是它的主力軍,而關鍵字則是士兵們手中的利器。對於一個需要經常馳騁疆場的C程序員來說,如果不能把這柄利器運用自如的話,那麼不僅會失去“一夫當關,萬夫莫開”的雄風,甚至還會傷及自身。因此,我開了這麼一個序列,嘗試將兵器庫裏的各種奇異兵器玩耍一遍。另外,這裏我介紹的關鍵字都是實踐中遇到的。


一. 不要再見外了-----extern

(1)前幾天在南理工車庫調試程序的時候,在編譯工程的時候,編譯器爆出這麼一個錯誤:Undefined reference to "getSockfdToServer"。很顯然,這說明編譯器並未找到getSockfdToServer函數的定義。起初,我以爲是因爲連接器沒有找到定義該函數的庫。於是,我仔細地檢查了相關的CMakeLists.txt文件,以及是否有包含該函數聲明的頭文件等等,可問題依然存在。就在心灰意冷之際,事情卻突然發生了轉機。在查看聲明該函數定義的頭文件中,我發現下面這個重要的東西被人註釋掉了。


#ifdef __cplusplus
   extern "C" {
#endif

......

#ifdef __cplusplus
  }
#endif

而定義該函數的庫文件是.cpp文件。顯然問題已經很清楚了,沒有了上面的那段代碼,編譯器在編譯getSockfdToServer的時候,就會按照C++的編譯方式進行。而我們的工程卻是用C的方式編譯的,所以連接器在庫裏找不到該函數的定義。extern "C“ 只是extern的一種用法之一。以下引用百度百科對這一用法的詳細敘述:

被extern "C"修飾的變量和函數是按照C語言方式編譯和連接的;  

未加extern “C”聲明時的編譯方式。  

首先看看C++中對類似C的函數是怎樣編譯的。作爲一種面向對象的語言,C++支持函數重載,而過程式語言C則不支持。函數被C++編譯後在符號庫中的名字與C語言的不同。例如,假設某個函數的原型爲:  

void foo( int x, int y );  該函數被C編譯器編譯後在符號庫中的名字爲_foo,而C++編譯器則會產生像_foo_int_int之類的名字(不同的編譯器可能生成的名字不同,但是都採用了相同的機制,生成的新名字稱爲“mangled name”)。_foo_int_int這樣的名字包含了函數名、函數參數數量及類型信息,C++就是靠這種機制來實現函數重載的。例如,在C++中,函數void foo( int x, int y )與void foo( int x, float y )編譯生成的符號是不相同的,後者爲_foo_int_float。  同樣地,C++中的變量除支持局部變量外,還支持類成員變量和全局變量。用戶所編寫程序的類成員變量可能與全局變量同名,我們以"."來區分。而本質上,編譯器在進行編譯時,與函數的處理相似,也爲類中的變量取了一個獨一無二的名字,這個名字與用戶程序中同名的全局變量名字不同。


(2)extern更多地是用來修飾變量。我們知道每個變量都有它的作用域,全局變量在該文件中任何地方都可引用,而局部變量則只能在一個特定的作用域內使用。有時工程中會出現這樣的情況:在幾個文件中可能都需要使用同一個變量。這時候extern便能滿足你這種訴求。例如,我們在a.c文件中定義了變量int a,如果要在b.c文件中引用變量a,只需要在b.c文件中這樣"extern int a"申明即可。當然,首先得保證變量a的鏈接屬性是外部鏈接的,即變量a首先得能夠在a.c文件中被引用,通常它應該是全局變量。另外,extern int a也可以寫在一個函數定義的開頭處,這樣的話,就只能在該函數內引用該變量。


(3)extern修飾函數跟修飾變量差不多。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章