C++ extern “C”的作用詳解
- 1.示例
- 2. 補充說明-C、C++編譯器
- 3. extern "C"使用要點
Reference:
- extern “C”的作用詳解
extern "c"
的主要作用就是為了能夠正确實作C++代碼調用其他C語言代碼。加上 extern “c” 後,會訓示編譯器這部分的代碼按C語言,而不是C++的方式進行編譯。
由于C++支援函數重載,是以編譯器編譯函數的過程中會将函數的參數類型也加到編譯後的代碼中,而不僅僅是函數名;而C語言并不支援函數重載,是以編譯C語言代碼的函數時不會帶上函數的參數類型,一般隻包括函數名。
這個功能十分有用處,因為在C++出現以前,很多代碼都是C語言寫的,而且很底層的庫也是C語言寫的。為了更好的支援原來的C代碼和已經寫好的C語言庫,需要在C++中盡可能的支援C,而 extern “c” 就是其中的一個政策。
這個功能主要用在以下情況:
- C++代碼調用C語言代碼;
- 在C++的頭檔案中使用;
- 在多人協同開發時,有的人比較擅長C語言,而有的比較擅長C++,這樣的情況下也會有用到。
1.示例
有moduleA、moduleB兩個子產品,B調用A中的代碼,其中A是用C語言實作的,而B是利用C++實作的,下面給出一種實作方法:
//moduleA頭檔案
#ifndef __MODULE_A_H //對于子產品A來說,這個宏是為了防止頭檔案的重複引用
#define __MODULE_A_H
int fun(int, int);
#endif
//moduleA實作檔案moduleA.c //子產品A的實作部分并沒有改變
#include"moduleA"
int fun(int a, int b)
{
return a+b;
}
//moduleB頭檔案
#idndef __MODULE_B_H //很明顯這一部分也是為了防止重複引用
#define __MODULE_B_H
#ifdef __cplusplus
//這一部分就是告訴編譯器,如果定義了__cplusplus(即如果是cpp檔案----cpp檔案預設定義了該宏),
// 則采用C語言方式進行編譯
extern "C"{
#include"moduleA.h"
#endif
… //其他代碼
#ifdef __cplusplus
}
#endif
#endif
//moduleB實作檔案 moduleB.cpp //B子產品的實作也沒有改變,隻是頭檔案的設計變化了
#include"moduleB.h"
int main()
{
cout<<fun(2,3)<<endl;
}
2. 補充說明-C、C++編譯器
由于 C 和 C++ 編譯器對函數的編譯處理是不完全相同的,尤其對于 C++ 來說,支援函數的重載,編譯後的函數一般是以函數名和形參類型來命名的。
例如函數
void fun(int, int)
編譯後的可能是
_fun_int_int
----不同編譯器可能不同,但都采用了相似機制,用函數名和參數類型來命名編譯後的函數名;而C語言沒有類似的重載機制,一般是利用函數名來指明編譯後的函數名的,對應上面的函數可能會是
_fun
這樣的名字。
是以,如果不加 extern “c”,在連結階段,連結器會從 moduleA 生成的目标檔案 moduleA.obj 中找 _fun_int_int 這樣的符号,顯然這是不可能找到的,因為 fun() 函數被編譯成了_fun 的符号,是以會出現連結錯誤。
如下面面試題:為什麼标準頭檔案都有類似的結構?
#ifndef __INCvxWorksh /*防止該頭檔案被重複引用*/
#define __INCvxWorksh
#ifdef __cplusplus //告訴編譯器,這部分代碼按C語言的格式進行編譯,而不是C++的
extern "C"{
#endif
/*…*/
#ifdef __cplusplus
}
#endif
#endif /*end of __INCvxWorksh*/
3. extern "C"使用要點
- 可以是如下的單一語句:
extern “C” double sqrt(double);
- 可以是複合語句, 相當于複合語句中的聲明都加了 extern “C”:
extern “C”
{
double sqrt(double);
int min(int, int);
}
- 可以包含頭檔案,相當于頭檔案中的聲明都加了extern “C” (不建議這樣寫,會有嵌套可能)
extern “C”
{
#include <cmath>
}
- 不可以将 extern “C” 添加在函數内部;
- 如果函數有多個聲明,可以都加 extern “C”, 也可以隻出現在第一次聲明中,後面的聲明會接受第一個連結訓示符的規則。