解析“extern”
1、 声明外部变量
//A.cpp int i;
void main() { } |
//B.cpp int i; |
Linking... B.obj : error LNK2005: "int i" (?i@@ 3HA) already defined in A.obj Debug/A.exe : fatal error LNK1169: one or more multiply defined symbols found Error executing link.exe.
A.exe - 2 error(s), 0 warning(s) |
//A.cpp
void main() { i = 100; //试图使用B中定义的全局变量 } |
//B.cpp int i; |
Compiling... A.cpp C:/Documents and Settings/wangjian/桌面/try extern/A.cpp(5) : error C2065: 'i' : undeclared identifier Error executing cl.exe.
A.obj - 1 error(s), 0 warning(s) |
//A.cpp
extern int i; void main() { i = 100; //试图使用B中定义的全局变量 } |
//B.cpp int i; |
2、 在C++文件中调用C方式编译的函数
int i;
int func(int t) { return 0; }
void main() { } |
COMM _i : DWORD
PUBLIC _func
PUBLIC _main |
PUBLIC ?i@@ 3HA ; i
PUBLIC ?func@@YAHH@Z ; func
PUBLIC _main |
可见,C方式编译下,变量名和函数名之前被统一加上了一个下划线,而C++编译后的结果却复杂的多,i变成了?i@@ 3HA,func变成了?func@@YAHH@Z。C++中的这种看似复杂的命名规则是为C++中的函数重载,参数检查等特性服务的。
多文件程序中的函数调用
一般情况下,工程中的文件都是CPP文件(以及头文件)。如下面的程序仅包含两个文件:A.CPP和B.CPP:
//A.CPP void func();
void main() { func(); } |
//B.CPP void func() { } |
需要注意的是,一般的程序都是通过包含头文件来完成函数的声明。拿本例来说,一般是创建一个头文件B.H,在头文件中加入声明语句void func(); 并且在A.CPP中加入包含语句:#include “B.H”。
在C++程序中,头文件的功能从函数声明被扩展为类的定义。
//A.CPP void func();
void main() { func(); } |
//B.C void func() { } |
Linking... A.obj : error LNK2001: unresolved external symbol "void __cdecl func(void)" (?func@@YAXXZ) Debug/A.exe : fatal error LNK1120: 1 unresolved externals Error executing link.exe.
A.exe - 2 error(s), 0 warning(s) |
call ?func1@@YAXXZ |
//A.CPP extern "C" { void func(); } void main() { func(); } |
3、 补充
//A.CPP
extern int i;
void main() { i = 100; } |
//B.C int i; |
Linking... A.obj : error LNK2001: unresolved external symbol "int i" (?i@@ 3HA) Debug/A.exe : fatal error LNK1120: 1 unresolved externals Error executing link.exe.
A.exe - 2 error(s), 0 warning(s) |
这是因为,在C方式编译下,i被重命名为_i,而在C++方式下,i会被重命名为?i@@ 3HA。
因而,我们只用extern int i;来声明还不够,必须告诉编译器,全局变量i是以C方式编译的, 它会被重命名为_i,而不是?i@@ 3HA。
我们修改A.CPP,如下:
//A.CPP
extern "C" { int i; } void main() {
i = 100; } |
程序正常通过编译和链接。
我们察看一下汇编代码,发现语句i = 100;被编译成了mov DWORD PTR _i, 100。