extern關鍵字

基本解釋:extern可以置於變量或者函數前,以標示變量或者函數的定義在別的文件中提示編譯器遇到此變量和函數時在其他模塊中尋找其定義。此外extern也可用來進行鏈接指定。

    也就是說extern有兩個作用,第一個,當它與"C"一起連用時,如: extern "C" void fun(int a, int b);則告訴編譯器在編譯fun這個函數名時按着C的規則去翻譯相應的函數名而不是C++的,C++的規則在翻譯這個函數名時會把fun這個名字變得面目全非,可能是fun@aBc_int_int#%$也可能是別的,這要看編譯器的"脾氣"了(不同的編譯器採用的方法不一樣),爲什麼這麼做呢,因爲C++支持函數的重載啊,在這裏不去過多的論述這個問題,如果你有興趣可以去網上搜索,相信你可以得到滿意的解釋!
    第二,當extern不與"C"在一起修飾變量或函數時,如在頭文件中: extern int g_Int; 它的作用就是聲明函數或全局變量的作用範圍的關鍵字,其聲明的函數和變量可以在本模塊活其他模塊中使用,記住它是一個聲明不是定義!也就是說B模塊(編譯單元)要是引用模塊(編譯單元)A中定義的全局變量或函數時,它只要包含A模塊的頭文件即可,在編譯階段,模塊B雖然找不到該函數或變量,但它不會報錯,它會在連接時從模塊A生成的目標代碼中找到此函數。

C++之父在設計C++之時,考慮到當時已經存在了大量的C代碼,爲了支持原來的C代碼和已經寫好C庫,需要在C++中儘可能的支持C,而extern "C"就是其中的一個策略。

 

試想這樣的情況:一個庫文件已經用C寫好了而且運行得很良好,這個時候我們需要使用這個庫文件,但是我們需要使用C++來寫這個新的代碼。如果這個代碼使用的是C++的方式鏈接這個C庫文件的話,那麼就會出現鏈接錯誤.

 

我們來看一段代碼:首先,我們使用C的處理方式來寫一個函數,也就是說假設這個函數當時是用C寫成的:

//f1.c
extern "C"
{
void f1()
{ return; }
}

編譯命令是:gcc -c f1.c -o f1.o 產生了一個叫f1.o的庫文件。

 

再寫一段代碼調用這個f1函數:

// test.cxx

//這個extern表示f1函數在別的地方定義,這樣可以通過

//編譯,但是鏈接的時候還是需要

//鏈接上原來的庫文件.

extern void f1();
int main()
{ 
f1();
return 0; 
} 

 

通過gcc -c test.cxx -o test.o 產生一個叫test.o的文件。然後,我們使用gcctest.o f1.o來鏈接兩個文件,可是出錯了,錯誤的提示是:test.o(.text + 0x1f):test.cxx: undefine reference to 'f1()'   也就是說,在編譯test.cxx的時候編譯器是使用C++的方式來處理f1()函數的,但是實際上鍊接的庫文件卻是用C的方式來處理函數的,所以就會出現鏈接過不去的錯誤:因爲鏈接器找不到函數。  

 

因此,爲了在C++代碼中調用用C寫成的庫文件,就需要用extern "C"來告訴編譯器:這是一個用C寫成的庫文件,請用C的方式來鏈接它們。  

比如,現在我們有了一個C庫文件,它的頭文件是f.h,產生的lib文件是f.lib,那麼我們如果要在C++中使用這個庫文件,我們需要這樣寫:

extern "C"
{
#include"f.h"
} 

 

回到上面的問題,如果要改正鏈接錯誤,我們需要這樣子改寫

test.cxx:extern "C" { extern voidf1(); }int main() { f1();return 0; } 

  

重新編譯並且鏈接就可以過去了.  

總結  C和C++對函數的處理方式是不同的.extern "C"是使C++能夠調用C寫作的庫文件的一個手段,如果要對編譯器提示使用C的方式來處理函數的話,那麼就要使用extern "C"來說明。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章