当这个世界还只有C的时候,是不需要extern "C"的。
但是,当C++出现之后,有时候,我们就需要extern "C"了。
那究竟是在什么样的情况下,我们需要用extern "C"呢?
有人说,是为了C能够调用C++,有人说是为了在C++中能调用C的库函数。是不是把你弄糊涂了?
先说说extern "C"是啥作用吧。
extern "C" 是告诉C++编译器,这个函数是完全兼容C的,不包含C++有而C中没有的特性的。并且告诉编译器,在生成目标文件的时候,使用C的方式生成函数名。
上面这句话有两个重点,
第一是 extern "C" 只有 C++编译器认得,C编译器是不认识的。
第二是 用C的方式生成函数名。什么叫 "用C的方式生成函数名"? C++编译器和C编译器生成函数名的方式是不同的。因为C++要支持函数重载,所以C++编译器在生成函数名的时候会把函数参数的类型加在函数名中。而C编译器就比较简单,直接在函数名字前加一个下划线搞定。
比如 void foo( int x ); 这样的函数
C编译器编译出来在符号库中的名字是_foo,而C++编译器编译出来在符号库中的名字可能是 _foo_int 这样的。
那么使用 extern "C" 有什么意义呢?
我觉得 ”为了C++中能调用C的库函数“ 这样的说法是正确的。
为什么?
考虑下面的情况,你有一个C实现的库,并用C编译器编译生成库文件。
假设这个库里有一个函数为 void foo( int );
在C++的某个类中,你要用这个foo函数,你在C++源文件中用
extern void foo( int );
引入。
这样在链接的时候出错了。
因为C++编译器在编译C++源文件的时候,认为void foo( int ); 在符号表中应该是
_foo_int 这个样子的。而在链接的时候找不到_foo_int,只有_foo。所以链接出错了。
怎么解决呢?
extern void foo( int );
改成
extern "C" void foo( int );
就行啦。
如果是直接include C的头文件的,那可以这样
extern "C" {
#include "HeaderOfC.h"
}
这样C++编译器就知道,这个foo是C的函数,生成名字的时候不需要带参数。这样链接的时候就没问题啦。
那么在今天,我们写一个C的库的时候,当然存在我们的库被C++的程序所使用的可能性。
我们不希望在C++的源码中引用我们的头文件的时候还要
extern "C" {
#include "yourlib.h"
}
这么麻烦。
所以我们在写C的库的头文件的时候主动的加上了 extern "C"。
但这里有一个问题,因为C编译器不认识extern "C"啊,所以就有了
宏 __cplusplus
对于C编译器,没有定义这个宏,而C++编译器定义了这个宏。
所以,C语言的头文件的标准写法是
#ifndef XXX_XXX_H
#define XXX_XXX_H
#ifdef __cplusplus
extern "C" {
#endif
/* 这里是头文件的内容 */
#ifdef __cplusplus
}
#endif
#endif