转自: http://blog.csdn.net/tiantangniao232/archive/2007/10/23/1838709.aspx
先看一小段程序:
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
块
为了解决上述问题,首先提出第一个问题?
Fun()中的局部静态变量 gg 在多次调用Fun()后(比如2次 )的值是多少?你肯定毫无犹豫地答到: 2
我如果问为什么?你可能毫无犹豫的答道:局部静态变量 gg 只是在第一次进入函数时被初始化。
变量 gg 真的是在第一次进入 函数时才被初始化的吗??!!
我们可以单步调试跟踪一下,你会发现调试时会直接跳过 static gg = 2;这一行。
因此我说变量 gg 在进入Fun函数之前就已经存在了,你信吗?
我们可以将断点插在 1 处 ,调试 Alt + 8 进入底层的汇编代码
12: static int a = 3; //对应着main函数中的声明,此时EBP = 0x0012FFC0
13: int b = nG;
00404BB8 mov eax,[nG (00476f90)] //这两句给 b 赋值 ,可以发现全局变量 nG 的地址是:0x00476F90
00404BBD mov dword ptr [ebp-4],eax // b 的地址是 0x0012FFBC
14: int c = a;
00404BC0 mov ecx,dword ptr [nG+8 (00476f98)] //这两句是给 a赋值,可以发现局部静态变量a的地址是
00404BC6 mov dword ptr [ebp-8],ecx // 0x00476F98,c的地址是:0x0012FFB8
15: Fun( );
00404BC9 call @ILT+790(Fun) (0040131b) --------看下面 Fun的汇编代码
16: static oo = 4;
17: c = oo;
00404BCE mov edx,dword ptr [nG+0Ch (00476f9c)] //局部静态变量 oo的地址是 0x00476F9c
00404BD4 mov dword ptr [ebp-8],edx
18: return 0;
00404BD7 xor eax,eax
19: }
Fun的汇编代码:
7: static gg = 2;
8: int local = gg;
004051B8 mov eax,[nG+4 (00476f94)]//这两句在给local赋值,可以发现 局部静态变量 gg的地址是
004051BD mov [nG (00476f90)],eax 0x00476F94
9: }
由上述可以发现 变量 nG gg a oo它们几个的内存地址很相近
0x00476F90:-----------------nG的地址
0x00476F94:-----------------gg的地址
0x00476F98:-----------------a 的地址
0x00476F9C:----------------oo的地址
我们可以发现这些全局变量和静态变量的内存地址,是在一块的。
总结:
我们通常都说main函数是程序的入口点,所以就很容易造成一种误解。认为程序一运行就进入了main,这是
不对的。既然main是函数,是函数就得被调用了才能执行。那么是谁调用了main函数呢?
通过调用堆栈我们发现,在main函数前还有一个函数:mainCRTStartup()。这个函数通常被称为启动代码,
由他对程序在进入main函数之前进行初始化(如加载动态链接库分配资源等等),毕竟程序的正常运行不是
仅仅依靠小小的main就行的。当然初始化过程中包含对全局变量和静态变量的内存分配。这里的全局变量可能好理解,但是静态变量就有点难理解了。比如Fun中的 gg 他是一个局部静态变量啊 为什么会在进入main函数之前就被初始化啦。这就是静态变量的特性,这就是通常我们为什么说静态变量的生命周期,和整个程序的生命周期是一样的。
下面简要的说一下本程序的运行流程:
首先由启动代码完成一些必要资源的加载,和全局变量、静态变量(你程序中的所有静态变量,包括局部的)
初始化,分配内存单元。
进入main函数,首先进行的操作是在栈上分配一块内存单元,用来分配函数中的局部变量(除了静态变量)和
参数的压栈以及函数地址的压栈。也就是说上面的main中的局部非静态变量 b 和 c就分配在此 内存块中,它 会在main函数返回后释放。
同理在进入Fun函数时,首先也会在栈上分配一块内存单元,用来分配Fun函数中的局部变量(除了静态变 量)和参数的压栈以及函数地址的压栈。比如Fun中的local就分配在此段内存块中,它会在Fun函数返回以后
被释放。
最后return 0返回,释放分给main函数的内存块,main函数结束以后由mainCRTStartup( )完成全局变量和
静态变量的释放,毕竟是由它调用mian函数的。
最后再强调一下,Fun中的局部静态变量不是第一次进入Fun时被初始化的,而是在进入main函数之前就已经
被初始化了。