對靜態變量和全局變量的認識

先看一小段程序:
#include<iostream>
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;    
}
     我們所關心的是這些變量如 nG  gg  a  等等在內存中的分佈如何?它們都緊挨着放在一塊?還是各有個的存儲

    爲了解決上述問題,首先提出第一個問題?
    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函數之前就已經
  被初始化了。
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章