关于"extern"

今天是国庆,既然没出去玩,大概得做点有意义的事情吧.决定对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

你可能感兴趣的:(extern)