声明外部变量
现代编译器一般采用按文件编译的方式,因此在编译时,各个文件中定义的全局变量是互相透明的,也就是说,在编译时,全局变量的可见域限制在文件内部。下面举一个简单的例子。创建一个工程,里面含有A.cpp和B.cpp两个简单的C 源文件:
//A.cpp
int i;
void main()
{
}
//B.cpp
int i;
这两个文件极为简单,在A.cpp中定义了一个全局变量i,在B中也定义了一个全局变量i。对A和B分别编译,都可以正常通过编译,但是进行链接的时候,却出现了错误,错误提示如下:
linking...
B.obj:errorLNK2005: "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时觉察不到B中也定义了i,同样,编译B时觉察不到A中也定义了i。但是在链接阶段,要将各个文件的内容“合为一体”,因此,如果某些文件中定义的全局变量名相同的话,在链接阶段就会报重复定义(one or more multiply defined symbols)的错误。
因此,各个文件中定义的全局变量名不可相同。
在链接阶段,编译产生的obj文件合并了A、B两文件的内容,这也是出现int i重复定义错误的原因。
举个例子
一个文件中定义的全局变量,可以在整个程序的任何地方被使用,举例说,如果A文件中定义了某全局变量,那么B文件中也可以使用该变量。修改我们的程序,加以验证:
//A.cpp
void main()
{i = 100; //试图使用B中定义的全局变量
}
//B.cpp
int i;
出现如下意料之中的编译错误,未定义int i错误(undeclared identifier Error),因为在链接之前A、B文件中的变量是彼此不可见的。
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)
编译器没有能够意识到,某个变量符号虽然不是本文件定义的,但是它可能是在其它的文件中定义的,为了避免错误的发生extern派上用场了。为上面的错误程序加上extern关键字后,顺利通过编译,链接,代码如下:
//A.cpp
extern int i;
void main()
{ i = 100; //试图使用B中定义的全局变量
}
//B.cpp
int i;
在C 文件中调用C方式编译的函数
相对于C,C 中新增了诸如重载等新特性,它们的编译有一些重要区别。将下面的小程序分别按C和C 方式编译,来探讨两种编译方式的区别。
int i;
int func(int t)
{return 0;
}
void main()
{
}
以C方式编译的结果如下:
COMM _i : DWORD
PUBLIC _func
PUBLIC _main
以C 方式编译的结果如下:
PUBLIC ?i@@ 3HA ; i
PUBLIC ?func@@YAHH@Z ; func
PUBLIC _main
可见,C方式编译下,变量名和函数名之前被统一加上了一个下划线,而C 编译后的结果却复杂的多,i变成了?i@@ 3HA ,func变成了?func@@YAHH@Z。C 中的这种看似复杂的命名规则是为C 中的函数重载,参数检查等特性服务的。
不同编译方式下的函数调用
如果在工程中,不仅有CPP文件,还有以C方式编译的C文件,函数调用就会有一些微妙之处。有如下CPP文件A.CPP和C文件B.C两个文件。
//A.CPP
void func();
void main()
{func();
}
//B.C
void func()
{
}
对A.CPP和B.C分别编译,都没有问题,但是链接时出现错误,原因就是C和CPP不同的编译方式产生的冲突。比如在上文中提到,C方式编译下,变量名和函数名之前被统一加上了一个下划线,而C 编译后的结果却复杂的多,i变成了?i@@ 3HA。
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)
此时,可以通过extern关键字,来帮助编译器解决上面提到的问题。对于本例,只需将A.CPP改成如下代码即可:
//A.CPP
extern "C"
{void func(); //引入C语言方式编译的函数或变量
}
void main()
{func();
}
声明:
本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。