env:
gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)
在c++中調(diào)用c語言寫的模塊時經(jīng)常在頭文件中加入這樣一段預(yù)處理命令:
#ifdef __cplusplus
extern "C" {
#endif
/*some c header or declaration*/
#ifdef __cplusplus
}
#endif
之所以要引入extern "C"(注: 引號中是大寫的C)缀棍, 是因為c++中存在overload即函數(shù)重載, 為了區(qū)別函數(shù)名相同參數(shù)不同的函數(shù), c++編譯器在編譯期間會將函數(shù)名和函數(shù)參數(shù)作為整體進行編譯來得到鏈接所需的符號;c語言中沒有overload, 編譯器直接以函數(shù)名作為鏈接符號, 無視函數(shù)名后面的參數(shù)膳帕。
請看以下例程:
例程一:
有以下2個模塊main.cc和add.c, 在main.cc中調(diào)用add.c中的函數(shù)add
/*main.cc模塊*/
#include <iostream>
//extern "C"
//{
extern int add(int a, int b);
//}
int main(int argc, char * argv[])
{
int s;
s = add(1, 2);
std::cout << "s = " << s << std::endl;
return 0;
}
/*add.c模塊*/
int add(int a, int b)
{
return a + b;
}
執(zhí)行以下命令:
g++ -c main.cc
gcc -c add.c
g++ main.o add.o -o test
則會報鏈接錯誤:
undefined reference to `add(int , int)', 意為找不到該函數(shù)定義。
執(zhí)行objdump -t main.o查看符號表發(fā)現(xiàn)main.cc中調(diào)用的外部函數(shù)add已被編譯為"00000000 UND 00000000 _Z3addii"(add后面的2個i為參數(shù)int, int 的縮寫), 明顯函數(shù)編譯后的鏈接符號與函數(shù)參數(shù)是有關(guān)系的。再執(zhí)行objdump -t add.o查看符號表發(fā)現(xiàn)add函數(shù)對應(yīng)的符號就是add。顯而易見鏈接器肯定找不到鏈接符號為_Z3addii的函數(shù), 因為我們從來沒有定義過。
試想: 其他模塊不動將add.c中的add函數(shù)改名為_Z3addii是否可以鏈接成功呢? 答案是肯定的牛隅, 但是這么寫代碼有啥意義呢?
例程二:
有以下2個模塊main.cc和add.c, 在main.cc中調(diào)用add.c中的函數(shù)add
將例程一中extern "C"的注釋打開, 如下所示:
/*main.cc模塊*/
#include <iostream>
extern "C"
{
extern int add(int a, int b);
}
int main(int argc, char * argv[])
{
int s;
s = add(1, 2);
std::cout << "s = " << s << std::endl;
return 0;
}
/*add.c模塊*/
int add(int a, int b)
{
return a + b;
}
執(zhí)行以下命令:
g++ -c main.cc
gcc -c add.c
g++ main.o add.o -o test
編譯鏈接正常, 執(zhí)行可執(zhí)行文件./test, 即可看到我們想要的結(jié)果:s = 3。此刻我們再次執(zhí)行命令objdump -t main.o看到main.cc中的調(diào)用的外部函數(shù)add被編譯為:"UND 00000000 add", 符號和函數(shù)名完全一致而沒有添加一些奇怪的東西酌泰!
總結(jié):
? extern "C"就是要告訴c++編譯器大括號里面聲明的函數(shù)要按照c語言的方式編譯成鏈接需要的符號媒佣。這樣c++在鏈接的時候才能找到對應(yīng)的c函數(shù)。