c++中关于extern的理解

来源:互联网 发布:three.js 全景图 编辑:程序博客网 时间:2024/05/29 03:15
众所周知 extern是表示声明的关键字
extern int i;/*这是声明*/int i;/*这是定义*/


 

虽然有人觉得第二行也是声明,但是根据c++ primer的说法,下面的确实是定义,因为这个时候i会被分配内存,而且声明是不会分配内存的。由分不分配内存作为声明和定义的判断标准的话,第二行确实是定义。

 

当然有的时候声明后也可以立即定义,如

extern int i = 1;/*这是声明+定义*/

 

在函数外部使用extern的时候,会非常容易。不过在函数内部使用extern(或许这样没什么意义),则会遇到很多让人迷惑的地方。

如下列代码:

void main(){    extern int i;    i = 1;}


 

乍一看觉得这样的代码没什么问题,先声明,然后再定义,很正确。但是这样实际上是错误的,会报一个重定义的错误(redefinition)。

误认为这段代码正确的原因可能是这样:很多人觉得先声明后定义是一件很正常的事情,然而这却不一定。这里有个概念模糊,确切的声明是形如下列代码的

extern int i;

 


而形如下列代码的,不是声明

 

int i;extern int i = 1;


我们常说的先声明后定义,是指的这样的情况

int i;i = 1;



 

但这其实是错误的概念。因为“int i;”这样的语句并不是声明,而是定义。

与上面这种误解恰恰相反,在使用extern作为声明的时候,其实声明往往出现在定义之后,而且应该出现在定义之后

举个例子,在函数外部写如下声明代码

extern int i;


通常是在别的源文件中定义好了i后,才会写这样一句声明,表明要用的i来自别的文件,而且是已经被定义好的i

而绝对不会先如上声明一次,然后在自己的源文件中又定义一次i(因为这样是多此一举)。所以说,声明往往是在定义之后的。

也就是说,见到了某个对象(如int i)的exten声明,往往代表i是已经被定义好了的。

也就是说,在效果上,声明≈定义。见到了某个对象的extern声明,代表这个对象已经被定义好了,就可以直接对其赋值或用其进行运算(当然之前要确保它是被初始化了的)。

理解了上面的,就能理解在函数体内怎么使用extern了。也能明白下面的代码错在哪了。

void main(){    extern int i;    int i = 1;}


 


因为extern int i;相当于指明某处已经定义过一个i了,接下来又要int i = 1;这显然是重定义了。

改成这样就是没问题的:


void main(){    extern int i;    i = 1;}


 


不过要注意,在适合的地方要确切存在i的定义

那么何谓适合的地方

我们知道通常c++的作用域是被大括号括起来的,最外层没有被括起来的地方,是最大的作用域,在这里定义的变量是全局变量,可以被任何地方访问。当然访问不是没有限制的,其中一种方法就是通过extern声明。在程序的任何地方,只要是用extern声明了一个全局变量,那这个全局变量就变得可以访问了。因为全局变量的作用域是整个程序。也就是说,最外层没有被括号括起来的地方,是存在定义的适合的地方。

实际上,只有最外层才是适合的地方,因为extern其实只能声明全局变量。下面的代码就是错误的,因为i是局部变量。extern int i会试图找寻一个已经被定义的全局变量i,但是却没找到,所以会出现fatal error LNK1120: 1 unresolved externals (无法连接的外部变量)的错误。


 

int main(){ int i = 1;{extern int i;cout<<i;}return 0;}


 下面的代码是正确的

int i = 3;int main(){ int i = 1;{extern int i;cout<<i;}return 0;}

而且输出的是3

代码改为为下面这样的话,输出的是1,原因是定义域。extern相当于在当前定义域中定义了一个变量,在这个定义域的外部是看不到这个变量的。

int i = 3;int main(){ int i = 1;{extern int i;cout<<i;}cout<<i;return 0;}


 

 

体会这几个例子,就能明白extern的一些特点。

1、使用于定义之后

2、只用于外部变量(即全局变量)

3、遵从普通变量的定义域划分规则
......

 

 

水平有限,又是特别仓促写的东西,有点不好理解请多包涵,有错误欢迎指正