C++的全局变量初始化问题——链接器的特性

来源:互联网 发布:C语言布尔变量怎么用 编辑:程序博客网 时间:2024/05/26 15:54

对于全局变量大家都知道,变量的初始化问题分为两个,一个是用常量来初始化变量,这个比较简单,不会涉及到什么问题;另一个初始化问题即全局变量使用其它变量来初始化,那么编译器在编译的时候是不会去计算的,所以这个初始化过程只能等到加载完毕了以后再去初始化,意思就是,在执行main函数之前有一个全局变量的初始化过程,这里说的全局变量只是指那些用其他全局变量初始化的变量,下面举个例子。

 int   a   =   5;    int   b   =   a; 即b的初始化使用了a。a和b都是全局变量,则在编译完成后,a的值就确定了,但是,b的值要等到加载以后才会进行初始化。

下面反汇编的图说明了这点:


这个道理比较简单,但是这个后面存在的问题是比较复杂的。

复杂也不复杂,简而言之,既然是在运行之前初始化第二类全局变量,问题的来源就是分段编译,因为如果源程序就是一个文件的话,应该不会存在第二类全局变量初始化的问题,以为所有变量使用前都得定义,但是分段编译的话,存在链接的先后顺序,即如果有一下两个文件,1.cpp和2.cpp

1.cpp如下:

extern int a;
int b=10+a;

2.cpp如下:

extern int b;
int x=10;
int a=10+x;

那么如果先链接1在链接2,则因为a在b后面初始化,那么b的初始化就会不正确(可以初始化),因为在编译的时候,对于那些要在运行前才初始化的全局变量,编译器一般都是赋予0,所以,上述b最终初始化的值是10;

如果以上链接顺序换一换的话,那么就能正确初始化。

关于全局变量的初始化,C语言和C++是有区别的。      
       在C语言中,只能用常数对全局变量进行初始化,否则编译器会报错。       
       在C++中,如果在一个文件中定义了int a = 5;要在另一个文件中定义int b = a;的话,前面必须对a进行声明:extern   int   a;否则编译不通过。即使是这样,int b = a;这句话也是分两步进行的:在编译阶段,编译器把b当作是未初始化数据而将它初始化为0;在执行阶段,在main被执行前有一个全局对象的构造过 程,int b = a;被当作是int型对象b的拷贝初始化构造来执行。    
      其实,准确地说,在C++中全局对象、变量的初始化是独立的,如果不是象int a   =   5;这样的已初始化数据,那么就是象b这样的未初始化数据。    
      而C++中全局对象、变量的构造函数调用顺序是跟声明有一定关系的,即在同一个文件中先声明的先调用。对于不同文件中的全局对象、变量,它们的构造函数调用顺序是未定义的,取决于具体的编译器。

对于那些使用对象类型的初始化问题则更复杂了,因为只有内建类型才会在编译是不能初始化的时候赋予0,那些抽象数据类型则直接会报错。这个应该是C++编程思想中,静态初始化相依性那一章想讲的内容。

当然在看深入理解计算机系统的时候,链接那章对于解析引用时候涉及到的链接顺序问题,460页的问题还不是很了解,因为我觉得这两部分内容矛盾,即解析引用强调要先链接有引用符号的文件,在链接有符号定义的文件(Unix中),但初始化相依性则强调先链接被引用的文件,在链接有引用的文件。可能是我的理解错了,再去看看CSAPP。