在 main (或 wmain/WinMain) 執行之前,C/C++ 運行庫 (CRT) 的啟動代碼完成關鍵初始化:
GetCommandLine/_acmdln/_wcmdln)。_environ/_wenviron)。errno, stdin/stdout/stderr 流結構等)。crtexe.c)mainCRTStartup / wmainCRTStartup
int mainCRTStartup(void) {
__security_init_cookie(); // /GS 安全餅乾初始化,防緩衝區溢出攻擊
return __tmainCRTStartup(); // 統一入口
}
__tmainCRTStartup該函數承擔了繁重的初始化與異常處理工作,簡化流程如下:
int __tmainCRTStartup(void) {
// 1. GUI 程序特有:解析命令行、獲取啟動信息
#ifdef _WINMAIN_
// ... GetStartupInfo, 解析 lpszCommandLine ...
#endif
// 2. 線程安全的單次初始化鎖 (__native_startup_lock)
// 防止多線程並發初始化 CRT (如 DLL 載入時)
// 3. 執行 C++ 類型初始化器 (__xi_a 到 __xi_z 段)
// #ifndef _SYSCRT -> _initterm_e(__xi_a, __xi_z) // 返回非0則失敗
// #else -> _initterm(__xi_a, __xi_z)
// 4. 執行 C++ 對象構造函數 (__xc_a 到 __xc_z 段)
// _initterm(__xc_a, __xc_z);
// __native_startup_state = __initialized;
// 5. TLS 動態初始化回調 (__dyn_tls_init_callback)
// 6. 啟用緩衝區檢查 (_CrtSetCheckCount)
// 7. 調用用戶入口點
#ifdef _WINMAIN_
// WinMain / wWinMain 參數準備與調用
mainret = WinMain(...);
#else
// 標準 main / wmain
#ifdef WPRFLAG
__winitenv = envp; mainret = wmain(argc, argv, envp);
#else
__initenv = envp; mainret = main(argc, argv, envp);
#endif
#endif
// 8. 終止流程
if (!managedapp) exit(mainret); // 觸發 atexit、析構函數
if (!has_cctor) _cexit(); // 僅執行 CRT 終止例程
return mainret;
}
class CSayHello {
public:
CSayHello() { cout << "Constructor CSayHello" << endl; }
~CSayHello() { cout << "Deconstructor CSayHello" << endl; }
};
CSayHello sayHello; // 全局對象
int main() {
CSayHello sayHello1; // 局部對象
return 0;
}
輸出順序:
Constructor CSayHello — 在 _initterm(__xc_a, __xc_z) 階段執行(main 前)。Constructor CSayHello — 進入 main,棧上構造局部對象。Deconstructor CSayHello — main 結束,局部對象離開作用域析構。Deconstructor CSayHello — exit() 過程中,CRT 遍歷終止列表析構全局對象。關鍵點:全局對象構造於 CRT 初始化階段,析構於 exit() 階段;局部對象遵循棧幂規則。異常拋出時,已構造對象會在棧展開時析構。