Welcome to zimmerman's blog!

初学->进阶->高手 有很长的路要走
美静->若英->我说 有许多的歌可听

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
今天是国庆,既然没出去玩,大概得做点有意义的事情吧.决定对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
posted on 2007-10-01 22:13  zim.NET  阅读(625)  评论(0编辑  收藏  举报