extern “C”主要是用于C++链接在C模块中定义的函数,或C++中编译的函数要在C中调用。
由于C++支持函数重载,因此编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名,也就是所谓的名字修饰;而C语言并不支持函数重载,因此编译C语言代码的名字修饰规则和C++是不同的。
如果C++中调用C实现的库函数,在编译链接的时候,还是按照C++名字修饰的规则寻找函数,会提示找不到对应的符号。加上extern "C"后,会指示链接器去寻找按照C修饰规则修饰后的函数名,而不是经过C++修饰的符号。注意,extern "C"在C中是语法错误,需要放在C++头文件中。
下面是1.cpp的代码:
#include <string.h> class test {}; int main() { char src[10] = "hehe"; char dest[10]; strcpy(dest, src); return 0; }
在1.cpp中,直接包含了<string.h>,这是一个C标准库文件,并且调用了strcpy标准C库函数。但是这里没有加extern “C”声明,也是可以编译成功的。
原因在于,在<string.h>中,有如下的声明:
#include <features.h> __BEGIN_DECLS ... /* Copy SRC to DEST. */ extern char *strcpy (char *__restrict __dest, const char *__restrict __src) ... __END_DECLS
问题的关键就在于__BEGIN_DECLS和__END_DECLS。在<features.h>文件中,包含了 <sys/cdefs.h>文件,而在该文件中,具有下面的定义:
/* C++ needs to know that types and declarations are C, not C++. */ #ifdef __cplusplus # define __BEGIN_DECLS extern "C" { # define __END_DECLS } #else # define __BEGIN_DECLS # define __END_DECLS #endif
所以,现在的标准C库文件,已经包含了extern “C”的声明了,可以在C++代码中直接使用C标准库函数。