最近經常看到頭文件中有
#ifdef __cplusplus extern "C" { #endif ....... #ifdef __cplusplus } #endif
這樣的語句,一直搞不清楚是什么意思,今天終於鬧明白了。
1.這種寫法的由來
C++比C晚出現,C++代碼如果能夠調用C語言的代碼,那么會更好的利用現有的成果,但是事實上C++代碼是無法直接調用C代碼的,這是因為C++編譯器在編譯.cpp文件時生成的函數名與C編譯器在編譯.c文件時生成的函數名是不一樣的。
C++為了支持重載,其編譯器在編譯完成后會對原有的函數名進行修改,比如
test(int i)和
test(int i, int j)
這兩個函數在編譯完成后可能就會被C++編譯器修改成:
_ZDtesti
_ZDtestii
這種樣式
但是C編譯器卻不會修改函數名,這樣問題就就來了,如果在一個C++代碼中包含一個聲明C函數的頭文件時,那么很可能在編譯完成后,頭文件中聲明的這個C函數名會被修改!這樣在C++代碼中使用這個C函數的時候就會發生找不到函數名的問題,事實上這個函數在C代碼中是存在的,只不過C++編譯器一廂情願的把函數名修改了。那么如何解決呢?
2.解決辦法
很簡單,顯式的告訴C++編譯器,這段代碼是用C語言編譯的函數,你就不要把函數名轉化為C++的格式了。
extern "C" { int socket_send(); // 明確的告訴C++編譯器,這是一個用C語言編譯的函數 }
這樣C++編譯器在執行這段代碼時,識別到extern "C"關鍵字,就會以C編譯器的方式來編譯括號內的代碼。
3.由此引發的問題
這樣雖然在C++編譯下沒有問題了,但是如果一個.c文件再去包含這個頭文件時,又會發生問題,因為extern "C"不是C語言的關鍵字,這樣.c文件又不能包含這個頭文件了。如何能夠既讓.cpp文件能夠包含這個頭文件,又能讓.c文件能夠包含這個頭文件呢,於是下面的寫法就產生了:
使用條件編譯的方式,如果判斷是C++的編譯器,就帶上extern "C",如果是C的編譯器就不帶extern "C",由此,問題得到妥善解決。需要注意的是:__cplusplus是C++編譯器內置的宏。
#ifdef __cplusplus extern "C" { #endif ....... #ifdef __cplusplus } #endif
