從彙編看c 中全域性物件和全域性變數

2021-08-21 21:20:43 字數 2727 閱讀 5976

先來看c++原始碼:

#include using

namespace

std;

class

x ~x() {}

};x ***(

1);//

全域性物件

int i = 2;//

全域性變數

intmain()

在**裡面定義了乙個全域性物件***和乙個全域性變數i,main函式什麼也不做。在定義全域性物件***處打乙個斷點,然後在vs2010裡面除錯,檢視物件***和變數i的記憶體,如下:

***的記憶體:

物件***的記憶體內容都被置為0,而不是無意義的數

i的記憶體:

可以看到,雖然i在物件***後面定義,但是,當斷點打在定義***處時,它記憶體值已經是2了。這是因為具有初始值的全域性變數,其值在連線時就被寫入了檔案。當使用者執行該檔案的時候,作業系統分析檔案中的資料,將相應資料寫入記憶體之中。因此,全域性變數誕生於所在執行檔案被作業系統載入之後,執行第一條**之前。(main函式並不是程式執行的第一條**)。

單步跟進後,我們會看到如下的構造物件***的彙編碼:

12: x ***(1);

//全域性物件

00bf4450

push

ebp

00bf4451

movebp,esp

00bf4453

subesp,0c0h

00bf4459

push

ebx

00bf445a

push

esi

00bf445b

push

edi

00bf445c

leaedi,[ebp-0c0h]

00bf4462

movecx,30h

00bf4467

moveax,0cccccccch

00bf446c

rep stos dword ptr es:

[edi]

00bf446e

push1;

壓入引數1

00bf4470

mov ecx,offset *** ;

獲取物件***的首位址

00bf4475

call

x::x ;

呼叫物件***的建構函式

00bf447a

push offset `dynamic atexit destructor for '

***' ;獲取物件***的析構**函式位址 ,傳遞給atexit函式

00bf447f call @ilt+100(_atexit) (0bf1069h) ;呼叫atexit函式,註冊物件***的析構**函式

00bf4484 add esp,4

00bf4487 pop edi

00bf4488 pop esi

00bf4489 pop ebx

00bf448a add esp,0c0h

00bf4490 cmp ebp,esp

00bf4492 call @ilt+305(__rtc_checkesp) (0bf1136h)

00bf4497 mov esp,ebp

00bf4499 pop ebp

00bf449a ret

上面彙編碼就是全域性物件***構造**函式(沒有原始碼對照)彙編碼,在**函式裡面,不僅呼叫了物件***的建構函式,而且將***的析構函式通過呼叫atexit函式進行了註冊。下面就來看看應用程式呼叫這個**函式的過程。

對於乙個應用程式,在呼叫main函式之前,編譯器其實已經做了很多事情,因此,main函式並不是應用程式入口。當應用程式被載入時,入口**是乙個叫maincrtstartup的函式(通過vs2010的呼叫堆疊可以看到),這個函式呼叫_tmaincrtstartup函式,_tmaincrtstartup函式又呼叫_initterm函式,它的c++原始碼如下:

static

void __cdecl _initterm ( _pvfv * pfbegin, _pvfv *pfend)

}

其中它的引數裡面的_pvfv*是乙個函式指標陣列,編譯器為每乙個全域性物件生成構造**函式,而構造**函式的位址就儲存在這個函式指標陣列裡。_pvfv的定義原型如下:

typedef void(_cdecl *_pvfv)(void);
從定義可以看出_pvfv指向的構造**函式為乙個無參無返回值的函式。由於**函式的型別被統一成_pvfv的形式,因此可以通過陣列統一管理和執行。

當mian函式執行完畢之後,由exit來結束程序,從而終止程式的進行。全域性物件的析構函式的呼叫也在其中。上面看到,在呼叫全域性物件***的構造**函式時,將其析構**函式通過atexit函式進行了註冊。因此,退出程式時會以註冊相反的順序呼叫註冊的析構**函式,並在析構**函式中呼叫全域性物件的真正析構函式,原理同呼叫構造**函式類似。

c 全域性變數 靜態全域性變數

全域性變數是靜態儲存方式,靜態全域性變數也是靜態儲存方式,這兩者在儲存方式上並無不同。區別 雖在於非靜態全域性變數的作用域是整個源程式,當乙個源程式由多個原始檔組成時,靜態全域性變數在各個原始檔中都是有效的。靜態區域性變數則限制了其作用域,只在定義該變數的原始檔內有效,在同一源程式的其它原始檔中不能...

PHP中全域性變數和超全域性變數

自定義全域性變數的作用域為當前的指令碼檔案的任意位置 函式或者方法啊之類的 但是要想用它們必須先執行一下 global variable語句 variable為要使用的全域性變數 或者是使用 global 變數名字 來呼叫。超全域性變數作用於也是為當前的指令碼檔案的任意位置,在使用的時候無需先執行 ...

C 靜態全域性變數和全域性變數的區別

靜態全域性變數 非靜態全域性變數 儲存方式 靜態儲存 靜態儲存 作用域定義該變數的原始檔內 所有原始檔 解釋 共同點 全域性變數 外部變數 的說明之前再冠以static 就構 成了靜態的全域性變數。全域性變數本身就是靜態儲存方式,靜態全域性變數當然也是靜態儲存方式。這兩者在儲存方式上並無不同。不同點...