using namespace std;
int nG = 1;
void Fun( )
{
static gg = 2;
int local = gg;
}
int main( )
{ ----------------1
static int a = 3;
int b = nG;
int c = a;
Fun( );
static oo = 4;
c = oo;
return 0;
}
塊
爲了解決上述問題,首先提出第一個問題?
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函數之前就已經
被初始化了。