今天是国庆,既然没出去玩,大概得做点有意义的事情吧.决定对C++的一些小知识点来个总结咯.GO ON.
以前只知道extern是声明外部变量的,其它知之甚少,既然知其不知,就要知之.
extern的作用总结起来就两点;
1.使用外部变量或函数
因为C++中文件的链接过程(link)存在着全局变量透明性,(参考[1])即在两个文件中声望两个同名的全局变量,那么在链接的时候就会报错,重复声明.既然在这时不同文件是相对透明的,那么我们要用其它文件的变量或函数就存在可能.而我们又不能再次声明(定义)它,所以引入了extern.
//
extern.cpp
extern
void
print(
char
*
p);
extern
int
i;
int
main(
int
argc,
char
*
argv[])
{
char
*
p
=
"
hello world!
"
;
print(p);
return
0
;
}
//
print.cpp
#include
"
stdio.h
"
int
i;
void
print(
char
*
s)
{
printf(
"
The string is %s\n
"
,s);
}
上面在main()调用print()前声明了外部的函数print(), 使用语句
extern
void
print(
char
*
p);还可以省略extern.
同样,看到上面的变量 i 没, 在extern.cpp里用了
extern
int
i;来引入i. 但这里为什么不能像上面对函数那样省略extern?我的理解是因为extern int i;对变量没有内存分配操作,而若省去则可能导致重复的对i定义.(并非声明),看错误说明大概就是:
print.obj : error LNK2005: "int i" (?i@@3HA) already defined in extern.obj
2.指示其它语言的函数或变量
比如我们要在C++语言中调用一个C语言的函数.
//
test_extern
extern
"
C
"
int
printf(
const
char
*
,);
int
main()
{
printf(
"
hello , extern\n
"
);
return
0
;
}
上述的代码包含一个头文件,但仍然是可编译运行的,因为printf()的原型已经有了,而且告诉编译器是外部的一个函数,我想编译器在链接的时候自己乖乖地去匹配了吧.^_^.
注意这里用了extern "C".
当然,我之所以说extern可以指示其它语言的函数或变量,这看你使用的编译器的实现.有的就可以用extern "Ada"或extern "FORTRAN".(参考[2])
如果你试着把extern "C"改为extern的话,你会不幸的链接失败.看如下的错误信息:
Linking
test.obj : error LNK2001: unresolved external symbol
"
int __cdecl printf(char const *,)
"
(
?
printf@@YAHPBDZZ)
Debug
/
test.exe : fatal error LNK1120:
1
unresolved externals
Error executing link.exe.
关键是
?
printf@@YAHPBDZZ, 别惊奇,如果你知道C语言的编译过程对函数及变量的重命名规则的话,这就是C++编译器对你的printf()函数的重命名.原因主要是为支持C++的新特性吧.
现在存在一个问题,用C语言编译的程序其在.obj中的文件是_printf()命名的. [重命名以下划线开头]而在C++中又是另一种命名方法,如何统一这两种差异,毕竟你要在CPP文件中使用一个以C编译规则得到的函数.就像上面,如果你不写extern "C"的话编译器就找不到你所要的
?
printf@@YAHPBDZZ
了,于是错误发生.
因此说extern "C" 是链接指示符.
关于extern 就说到这里.如有错误请指正.
参考资料:
[1] keen 专栏:
http://blog.csdn.net/keensword/archive/2005/06/23/401114.aspx
[2] Lippman <C++ Primer>CH7.7 CH8.2