printf("Hello World\n"); —— 這行代碼帶領無數程序員入門。但從源碼到可執行文件,再到進程啟動、CRT 初始化、最終進入 main,中間發生了什麼?本系列將剝開層層外衣,基於 **Windows 7 + Visual Studio 2010 (MSVC)** 環境,深入 CRT 源碼、反彙編與動態調試,還原程序完整生命週期。
VS 專案屬性 Subsystem(子系統) 決定入口點:
| Subsystem | 預定義宏 | 連接器選項 | CRT 入口函數 | 用戶入口 |
|---|---|---|---|---|
| Console (/SUBSYSTEM:CONSOLE) | _CONSOLE | /SUBSYSTEM:CONSOLE | mainCRTStartup | main / wmain |
| Windows (/SUBSYSTEM:WINDOWS) | _WINDOWS | /SUBSYSTEM:WINDOWS | WinMainCRTStartup | WinMain / wWinMain |
關鍵認知:
/SUBSYSTEM 寫入 mainCRTStartup 或 WinMainCRTStartup。crt0.c 等)負責:**堆初始化、I/O 緩衝區建立、C++ 全局對象構造、命令行參數解析(argv/argc)、環境變量準備**,最後調用用戶入口(main/WinMain)。main 返回值會被 CRT 捕獲並傳給 ExitProcess。VS 專案屬性 Character Set 影響兩個維度:
_UNICODE / _MBCS → 控制 TCHAR、_T()、Windows API 版本(MessageBoxW vs MessageBoxA)、CRT 字符串函數(_tcscpy 等)。int main() → 連接 mainCRTStartupint wmain() → 連接 wmainCRTStartupWinMain / wWinMain即:Character Set 宏只影響編譯,不影響連接器選擇哪個 CRT 入口。若專案設為 Unicode 但寫 main(),仍進入 ANSI 版 CRT 入口,命令行參數為 char**,需自行轉換。
| Runtime Library | 宏定義 | 庫文件 | 特點 |
|---|---|---|---|
| /MT (Static Release) | _MT, NDEBUG | libcmt.lib | CRT 代碼內嵌 EXE,體積大,無依賴,多 EXE 共享 CRT 狀態有風險 |
| /MTd (Static Debug) | _MT, _DEBUG | libcmtd.lib | 含調試檢查,體積更大 |
| /MD (Dynamic Release) | _MT, _DLL, NDEBUG | msvcrt.lib (導入庫) | 依賴 msvcrXXX.dll,體積小,系統級共享,需部署 VC++ Redistributable |
| /MDd (Dynamic Debug) | _MT, _DLL, _DEBUG | msvcrtd.lib | 調試版 DLL 依賴 |
本系列聚焦 **靜態鏈接(/MT)** 下的 CRT 初始化流程(crt0.c 等),動態鏈接(crtexe.c)略有不同(由 DLL 入口點 DllMain 觸發初始化)。
Hello World 的「隱形冰山」:
mainCRTStartup/WinMainCRTStartup)下期預告:從 CreateProcess 到主執行緒啟動,再到 mainCRTStartup 具體做了什麼(堆、I/O、全局構造、SEH、參數解析……),敬請期待。