eg.
#ifdef __cplusplus
extern "C" {
#endif
/*...*/
#ifdef __cplusplus
}
extern "C" 包含双重含义,从字面上即可得到:首先,被它修饰的目标是“extern”的;其次,被它修饰的目标是“C”的。让我们来详细解读这两重含义。
被extern "C"限定的函数或变量是extern类型的;
extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。
被extern "C"修饰的变量和函数是按照C语言方式编译和连接的;
作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为:
void foo( int x, int y );
该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为“mangled name”)。_foo_int_int这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。
如果这个函数在C中编译成库,目标文件中函数名为_func,当这个函数中C++中被调用时,C++的编译器就会到目标文件中寻找_foo_int_int,结果找不到,出错。
所以为了防止这种问题,在C++调用时,将函数声明前加个extern "C" 告诉C++的编译器,不要对名字再进修饰,而直接去找_func。同样在C++中编译的函数,如果想让C来使用,通常也加上extern "C"在编译时将函数名按C的风格进行修饰。
.可以包含头文件,相当于头文件中的声明都加了extern "C"
extern "C"
{
#i nclude <cmath>
}
extern "C"
{
double sqrt(double);
int min(int, int);
}
接下来,我们来看下#ifdef _cplusplus/#endif _cplusplus的作用。很明显#ifdef/#endif、#ifndef/#endif用于条件编译,#ifdef _cplusplus/#endif _cplusplus——表示如果定义了宏_cplusplus,就执行#ifdef/#endif之间的语句,否则就不执行。
在这里为什么需要#ifdef _cplusplus/#endif _cplusplus呢?因为C语言中不支持extern "C"声明,如果你明白extern "C"的作用就知道在C中也没有必要这样做,这就是条件编译的作用!在.c文件中包含了extern "C"时会出现编译时错误。
C++中调用C的代码
假设一个C的头文件cHeader.h中包含一个函数print(int i),为了在C++中能够调用它,必须要加上extern关键字(原因在extern关键字那节已经介绍)。它的代码如下:
1 2 3 4 5 6 | #ifndef C_HEADER #define C_HEADER extern void print( int i); #endif C_HEADER |
相对应的实现文件为cHeader.c的代码为:
1 2 3 4 5 6 | #include <stdio.h> #include "cHeader.h" void print( int i) { printf ( "cHeader %d\n" ,i); } |
现在C++的代码文件C++.cpp中引用C中的print(int i)函数:
1 2 3 4 5 6 7 8 9 | extern "C" { #include "cHeader.h" } int main( int argc, char ** argv) { print(3); return 0; } |
------------------------------------
extern用在变量声明中常常有这样一个作用,你在*.c文件中声明了一个全局的变量,这个全局的变量如果要被引用,就放在*.h中并用extern来声明。