首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C/C++程序啟動流程深度剖析:從CRT入口到main函數的完整旅程

     編輯:關於C語言

啟動函數的核心職責

在 main (或 wmain/WinMain) 執行之前,C/C++ 運行庫 (CRT) 的啟動代碼完成關鍵初始化:

  1. 獲取命令行參數指針 (GetCommandLine/_acmdln/_wcmdln)。
  2. 獲取環境變量塊指針 (_environ/_wenviron)。
  3. 初始化 CRT 全局變量(如 errno, stdin/stdout/stderr 流結構等)。
  4. 調用所有全局/靜態 C++ 對象的構造函數(靜態初始化後的動態初始化階段)。

Windows CRT 入口點源碼剖析 (基於 crtexe.c)

1. 主入口:mainCRTStartup / wmainCRTStartup


int mainCRTStartup(void) {
    __security_init_cookie(); // /GS 安全餅乾初始化,防緩衝區溢出攻擊
    return __tmainCRTStartup(); // 統一入口
}

2. 核心邏輯:__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;
}

輸出順序:

  1. Constructor CSayHello — 在 _initterm(__xc_a, __xc_z) 階段執行(main 前)。
  2. Constructor CSayHello — 進入 main,棧上構造局部對象。
  3. Deconstructor CSayHello — main 結束,局部對象離開作用域析構。
  4. Deconstructor CSayHello — exit() 過程中,CRT 遍歷終止列表析構全局對象。
關鍵點:全局對象構造於 CRT 初始化階段,析構於 exit() 階段;局部對象遵循棧幂規則。異常拋出時,已構造對象會在棧展開時析構。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved