先來看c++原始碼:
#include using在**裡面定義了乙個全域性物件***和乙個全域性變數i,main函式什麼也不做。在定義全域性物件***處打乙個斷點,然後在vs2010裡面除錯,檢視物件***和變數i的記憶體,如下:namespace
std;
class
x ~x() {}
};x ***(
1);//
全域性物件
int i = 2;//
全域性變數
intmain()
***的記憶體:
物件***的記憶體內容都被置為0,而不是無意義的數
i的記憶體:
可以看到,雖然i在物件***後面定義,但是,當斷點打在定義***處時,它記憶體值已經是2了。這是因為具有初始值的全域性變數,其值在連線時就被寫入了檔案。當使用者執行該檔案的時候,作業系統分析檔案中的資料,將相應資料寫入記憶體之中。因此,全域性變數誕生於所在執行檔案被作業系統載入之後,執行第一條**之前。(main函式並不是程式執行的第一條**)。
單步跟進後,我們會看到如下的構造物件***的彙編碼:
12: x ***(1);上面彙編碼就是全域性物件***構造**函式(沒有原始碼對照)彙編碼,在**函式裡面,不僅呼叫了物件***的建構函式,而且將***的析構函式通過呼叫atexit函式進行了註冊。下面就來看看應用程式呼叫這個**函式的過程。//全域性物件
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
對於乙個應用程式,在呼叫main函式之前,編譯器其實已經做了很多事情,因此,main函式並不是應用程式入口。當應用程式被載入時,入口**是乙個叫maincrtstartup的函式(通過vs2010的呼叫堆疊可以看到),這個函式呼叫_tmaincrtstartup函式,_tmaincrtstartup函式又呼叫_initterm函式,它的c++原始碼如下:
static其中它的引數裡面的_pvfv*是乙個函式指標陣列,編譯器為每乙個全域性物件生成構造**函式,而構造**函式的位址就儲存在這個函式指標陣列裡。_pvfv的定義原型如下:void __cdecl _initterm ( _pvfv * pfbegin, _pvfv *pfend)
}
typedef void(_cdecl *_pvfv)(void);從定義可以看出_pvfv指向的構造**函式為乙個無參無返回值的函式。由於**函式的型別被統一成_pvfv的形式,因此可以通過陣列統一管理和執行。
當mian函式執行完畢之後,由exit來結束程序,從而終止程式的進行。全域性物件的析構函式的呼叫也在其中。上面看到,在呼叫全域性物件***的構造**函式時,將其析構**函式通過atexit函式進行了註冊。因此,退出程式時會以註冊相反的順序呼叫註冊的析構**函式,並在析構**函式中呼叫全域性物件的真正析構函式,原理同呼叫構造**函式類似。
c 全域性變數 靜態全域性變數
全域性變數是靜態儲存方式,靜態全域性變數也是靜態儲存方式,這兩者在儲存方式上並無不同。區別 雖在於非靜態全域性變數的作用域是整個源程式,當乙個源程式由多個原始檔組成時,靜態全域性變數在各個原始檔中都是有效的。靜態區域性變數則限制了其作用域,只在定義該變數的原始檔內有效,在同一源程式的其它原始檔中不能...
PHP中全域性變數和超全域性變數
自定義全域性變數的作用域為當前的指令碼檔案的任意位置 函式或者方法啊之類的 但是要想用它們必須先執行一下 global variable語句 variable為要使用的全域性變數 或者是使用 global 變數名字 來呼叫。超全域性變數作用於也是為當前的指令碼檔案的任意位置,在使用的時候無需先執行 ...
C 靜態全域性變數和全域性變數的區別
靜態全域性變數 非靜態全域性變數 儲存方式 靜態儲存 靜態儲存 作用域定義該變數的原始檔內 所有原始檔 解釋 共同點 全域性變數 外部變數 的說明之前再冠以static 就構 成了靜態的全域性變數。全域性變數本身就是靜態儲存方式,靜態全域性變數當然也是靜態儲存方式。這兩者在儲存方式上並無不同。不同點...