例: 两个文件: c文件:C.c
|
***********************************************
int external=5; //全局变量,缺省为extern。
int func() //全局函数,缺省为extern。
{
return external;
}
***********************************************
cpp文件:CPP.cpp
***********************************************
#include "iostream"
using namespace std;
#ifdef __cplusplus
extern "C"
{
#endif
extern int external; //告诉编译器extern是在别的文件中定义的int,这里并不会为其分配存储空间。
extern int func(); //虽然这两个都是在extern "C"的{}里,但是仍然要显式指定extern,否则报错。
#ifdef __cplusplus //不仅仅是函数,变量也要放在extern "C"中。
}
#endif
void main(void)
{
cout<<"the value of external in c file is: "<<external<<endl;
external=10;
cout<<"after modified in cpp is : "<<func()<<endl;
}
***********************************************
在讨论extern "C"之前先来讨论extern。
1、C/C++里全局变量和全局函数的定义缺省是extern的。即如果一个project由好几个文件组成,那么在A文件的全局作用域中定义了全局变量或者全局函数,默认情况下在其他文件中是可见的,即其他的文件只要在自己的全局作用域中用extern显式声明A中的全局变量和函数,就可以使用A中定义的全局变量和全局函数。
2、需要注意的一点是,extern int external 这样的声明并不为external分配内存空间。这里只是一个声明,它告诉编译器 external 这个变量是在其他文件中定义。因此,在编译的时候即使找不到external的定义也不会报错,因为连接的时候会在其他文件的obj中找到external。
3、cout<<"the value of external in c file is: "<<external<<endl;
external=10;
cout<<"after modified in cpp is : "<<func()<<endl;
用这三句代码来说明extern:变量external是在C.c文件中定义的,CPP.cpp只是声明了一下,它告诉编译器CPP中用到的external是在别的文件中定义的。首先,打印出external的值,为5(C文件中定义externl为5,这更加说明了CPP中并不为external开辟新空间,否则应该为0),然后,在CPP文件中将external改为10,通过调用func()显式external的值。func()是C中的函数,它返回external的值,结果打印出10(进一步说明了external定义在C,使用在CPP)。
4、声明的时候,如果去掉变量前面的extern,将会出现连接错误,提示定义了两个同名变量。
5、与extern对应的是static。在全局作用域里用static显式声明的变量和函数说明它们只能供其所在的文件使用,其他文件对其不可见;如果是在模块中声明一个static变量,则这个变量的作用域还是所在模块,但是生命周期延长到程序结束。
再来看extern "C"。
extern "C" 的引用就是为了解决C++语言和C语言的混合编程问题。
C++支持的函数重载机制导致了C和C++编译机制的不同。
比如对一个函数
void foo( int x, int y );
由C编译器编译后符号库中的名字为_foo;而C++编译器编译后则为_foo_int_int,称为mangled name。C++正是靠这种编译机制实现了重载,比如另有一个重载函数void foo( int x, floaty );则编译后符号库中的名字为_foo_int_float。
这样就容易理解了,一个用C编写和编译的函数,如果需要在一个C++程序中调用和使用它,必须用extern "C",因为extern "C"能够保证对调用的C函数采用C的方式对其进行编译;否则,由于编译后符号库的名字不匹配,连接器在C的obj中找不到匹配的函数,则出现连接错误。
值得注意的是:不仅仅是全局函数,使用C中定义的全局变量也要放在extern "C"的{}中。
extern "C"中也可以添加整个C的头文件(#include)。
由于C不支持extern "C",所以出现了源文件中的条件编译语句(#ifdef...#endif)。
查看obj文件中符号库的方法:
vc安装目录的bin目录下有个应用程序dumpbin.exe。用如下命令行语句:
dumpbin.exe filename.obj /symbols /out:show.txt ( /out:show.txt 是将输出结果重定向到show.txt文件)