C++中extern "C"的设立动机是实现C++与C及其它语言的混合编程。
通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。
例如,如果模块B欲引用该模块A中定义的全局变量和函数时只需包含模块A的头文件即可。这样,模块B中调用模块A中的函数时,在编译阶段,模块B虽然找不到该函数,但是并不会报错;它会在连接阶段中从模块A编译生成的目标代码中找到此函数。
与extern对应的关键字是static,被它修饰的全局变量和函数只能在本模块中使用。因此,一个函数或变量只可能被本模块使用时,其不可能被extern “C”修饰。
被extern "C"修饰的变量和函数是按照C语言方式编译和连接的。
与extern对应的关键字是static,被它修饰的全局变量和函数只能在本模块中使用。因此,一个函数或变量只可能被本模块使用时,其不可能被extern “C”修饰。
被extern "C"修饰的变量和函数是按照C语言方式编译和连接的。
// 模块A头文件 moduleA.h
int foo( int x, int y );
在模块B中引用该函数:
// moduleB.cpp
#include "moduleA.h"
foo(2,3);
// moduleB.cpp
#include "moduleA.h"
foo(2,3);
实际上,在连接阶段,连接器会从模块A生成的目标文件moduleA.obj中寻找_foo_int_int这样的符号!
加extern "C"声明后,模块A的头文件变为:
// 模块A头文件 moduleA.h
extern "C" int foo( int x, int y );
// 模块A头文件 moduleA.h
extern "C" int foo( int x, int y );
(1)模块A编译生成foo的目标代码时,没有对其名字进行特殊处理,采用了C语言的方式;
(2)连接器在为模块B的目标代码寻找foo(2,3)调用时,寻找的是未经修改的符号名_foo。
如果在模块A中函数声明了foo为extern "C"类型,而模块B中包含的是extern int foo( int x, int y ) ,则模块B找不到模块A中的函数;反之亦然。
在C语言的头文件中,对其外部函数只能指定为extern类型,C语言中不支持extern "C"声明,在.c文件中包含了extern "C"时会出现编译语法错误。在C中引用C++语言中的函数和变量时,C++的头文件需添加extern "C",但是在C语言中不能直接引用声明了extern "C"的该头文件,应该仅将C文件中将C++中定义的extern "C"函数声明为extern类型。例如:
//C++头文件 a.h
extern "C" int foo( int x, int y );
extern "C" int foo( int x, int y );
//C++实现文件 a.cpp
#include "a.h"
int foo( int x, int y ){return x + y;}
#include "a.h"
int foo( int x, int y ){return x + y;}
/* C实现文件 b.c
这样会编译出错:#include "a.h" */
extern int foo( int x, int y );
int main( int argc, char* argv[] ){
这样会编译出错:#include "a.h" */
extern int foo( int x, int y );
int main( int argc, char* argv[] ){
}