C/C++语言中extern关键字的用法解析与实例
单片机与嵌入式 2023-11-29

声明外部变量

现代编译器一般采用按文件编译的方式,因此在编译时,各个文件中定义的全局变量是互相透明的,也就是说,在编译时,全局变量的可见域限制在文件内部。下面举一个简单的例子。创建一个工程,里面含有A.cpp和B.cpp两个简单的C++源文件:

//A.cppint i;void main(){}
//B.cppint i;

这两个文件极为简单,在A.cpp中定义了一个全局变量i,在B中也定义了一个全局变量i。对A和B分别编译,都可以正常通过编译,但是进行链接的时候,却出现了错误,错误提示如下:

Linking...B.obj : error LNK2005: "int i" (?i@@ 3HA ) already defined in A.objDebug/A.exe : fatal error LNK1169: one or more multiply defined symbols foundError 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.cppvoid main(){ i = 100; //试图使用B中定义的全局变量}
//B.cppint 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 identifierError executing cl.exe.A.obj - 1 error(s), 0 warning(s)

编译器没有能够意识到,某个变量符号虽然不是本文件定义的,但是它可能是在其它的文件中定义的,为了避免错误的发生extern派上用场了。为上面的错误程序加上extern关键字后,顺利通过编译,链接,代码如下:

//A.cppextern int i;void main(){ i = 100; //试图使用B中定义的全局变量}
//B.cppint i;

在C++文件中调用C方式编译的函数

相对于C,C++中新增了诸如重载等新特性,它们的编译有一些重要区别。将下面的小程序分别按C和C++方式编译,来探讨两种编译方式的区别。

int i;int func(int t){ return 0;}void main(){}

以C方式编译的结果如下:

COMM     _i : DWORDPUBLIC    _funcPUBLIC _main

以C++方式编译的结果如下:

PUBLIC ?i@@ 3HA         ; iPUBLIC    ?func@@YAHH@Z ; funcPUBLIC    _main

可见,C方式编译下,变量名和函数名之前被统一加上了一个下划线,而C++编译后的结果却复杂的多,i变成了?i@@ 3HA ,func变成了?func@@YAHH@Z。C++中的这种看似复杂的命名规则是为C++中的函数重载,参数检查等特性服务的。

不同编译方式下的函数调用

如果在工程中,不仅有CPP文件,还有以C方式编译的C文件,函数调用就会有一些微妙之处。有如下CPP文件A.CPP和C文件B.C两个文件。

//A.CPPvoid func();void main(){ func();}

//B.Cvoid 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 externalsError executing link.exe.A.exe - 2 error(s), 0 warning(s)

此时,可以通过extern关键字,来帮助编译器解决上面提到的问题。对于本例,只需将A.CPP改成如下代码即可:

//A.CPPextern "C"{ void func(); //引入C语言方式编译的函数或变量}void main(){ func();}



声明: 本文转载自其它媒体或授权刊载,目的在于信息传递,并不代表本站赞同其观点和对其真实性负责,如有新闻稿件和图片作品的内容、版权以及其它问题的,请联系我们及时删除。(联系我们,邮箱:evan.li@aspencore.com )
0
评论
  • 相关技术文库
  • C语言
  • 编程
  • 软件开发
  • 程序
下载排行榜
更多
评测报告
更多
广告