内存中的static、const实现形式
最近在考虑下半年找工作的事情,看了不少面试题目,其中还是蛮有收获的,把基础好好复习了一遍。比如这个题目,static、const现形式,static和const类型的变量在写程序的时候也写了很多,不过对编译器内部对其实现知之甚少。所以借这次机会好好百度谷歌了一番。
static实现形式
我们都知道,static变量只能初始化一次,这个是怎么实现的呢?小齐的网易博客里面作者写的很清楚: 代码如下:
1 int main(){ 2 for (int i(10); i > 0; --i) 3 { 4 fun(i) ; 5 } 6 7 return 0; 8 } 9 10 void fun(int i) 11 { 12 static int n = i ; 13 int *p = &n ; 14 cout << n << " " ; 15 16 ++n ; 17 }
因为static变量只能被初始化一次,所以第12行的初始化语句只会被执行一次,但是以后每次都会执行++n的操作,所以输出的结果是:
10 11 12 13 14 15 16 17 18 19
之后作者在VS下面对上述程序进行了DEBUG调试,发现第一次n被赋值之前内存如下:
0042E058 00 00 00 00 ....
0042E05C 00 00 00 00 .... // 中间这个为n的内存地址
0042E060 00 00 00 00 ....
当初始化语句执行完毕,内存内容如下:
0042E058 01 00 00 00 ....
0042E05C 0A 00 00 00 ....// n
0042E060 00 00 00 00 ....
作者继续执行,当for循环执行的时候,再次对static n初始化的时候,却发现n值不会等于i,而是继续保留原来的值。由此作者推断上面的那个0x01是不是就是标志n已经被初始化的标志位。即当要对n初始化的时候,就会检查上面的0042E058单元中对应的标志位是否是1,若是1,则说明已经初始化,若不是1,则进行初始化。
鉴于此,作者改进了fun函数,如下:
void fun(int i) { static int n = i ; int *p = &n ; cout << n << endl ; ++n ; p--; *p=0; }
即每次修改0042E058内容清零,使得可以反复对n初始化,做了上述改动之后,函数执行的结果如下:
10 9 8 7 6 5 4 3 2 1
得到证实了,即即当要对static初始化的时候,就会检查上一单元中对应的标志位是否是1,若是1,则说明已经初始化,若不是1,则进行初始化。
之后作者又做了实验,他设定了两个static变量:
void fun(int i) { static int n1 = i ; static int n2 = i ; int *p = &n1 ; cout << n1 << endl ; ++n1 ; p--; *p=0; }
观察单元发现,当执行static赋值之前,内存单元内容如下:
0042E058 00 00 00 00 ....
0042E05C 00 00 00 00 .... // n1
0042E060 00 00 00 00 .... // n2
当执行完static int n1 = i 语句之后,内存的值变成这样了:
0042E058 01 00 00 00 ....
0042E05C 0A 00 00 00 ....
0042E060 00 00 00 00 ....
接着我们再单步static int n2 = i,则执行内存的值变成这样:
0042E058 03 00 00 00 ....
0042E05C 0A 00 00 00 ....
0042E060 0A 00 00 00 ....
这样就很明显了,编译器分别用一位来表示一个static变量是否已经始化。
const实现形式就比较简单了,作者想使用地址的形式改变const常量的值,可是没有成功,作者查看汇编代码,原来是编译器直接将常量类型的换成对应的数值了。这样在执行的时候直接使用数值替换。
原文:http://www.cnblogs.com/havePassed/p/3559848.html