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

Windows 程式設計入門(四):從 libc.lib 看 CRT 靜態單執行緒庫原始碼

     編輯:關於C語言

C 執行期庫(CRT)版本總覽

VC6 提供 6 種 CRT 組合:單/多執行緒 × 靜態/動態連結 × Debug/Release。對應的 .lib 檔案與 cl 選項如下:

模型描述連結庫編譯選項
ST單執行緒、靜態LIBC.LIB/ML
MT多執行緒、靜態LIBCMT.LIB/MT
DLL多執行緒、動態MSVCRT.LIB/MD
XSTST Debug 版LIBCD.LIB/MLd
XMTMT Debug 版LIBCMTD.LIB/MTd
XDLLDLL Debug 版MSVCRTD.LIB/MDd

CRT 版本選項圖示

取得 CRT 原始碼

安裝 VC6 時勾選「CRT Source Code」,即可在 VC98\CRT\SRC 目錄找到完整原始碼(含 stdio.h、string.h、C++ STL 標頭等)。面對成百上千檔案,如何切入?關鍵在於「連結器錯誤訊息」。

從連結錯誤追蹤關鍵符號

前文使用 /Zl(不帶預設庫)編譯 hello.c 並連結時,出現兩個 LNK2001 錯誤:

  • _printf:printf 函式實作符號
  • _mainCRTStartup:程式真正入口點符號

這兩個符號均定義於 LIBC.LIB 中。_printf 對應標準輸出函式,_mainCRTStartup 則是 EXE 實際進入點,負責 CRT 初始化後再呼叫使用者的 main()。

mainCRTStartup 原始碼探秘(crt0.c)

在 CRT\SRC 搜尋 mainCRTStartup,找到 crt0.c。其核心流程(簡化版):

int WINAPI mainCRTStartup() {
    // 1. 初始化 CRT:堆疊、堆積、I/O、區域設定、引數解析...
    _heap_init();        // 建立 CRT 堆積
    _ioinit();           // 初始化標準串流 stdin/stdout/stderr
    // 2. 取得命令列參數、環境變數
    // 3. 呼叫使用者 main / wmain / WinMain / wWinMain
    int ret = main(__argc, __argv, __envp);
    // 4. 執行 atexit 登錄函式、關閉 I/O、釋放資源
    exit(ret);
}

原始碼中大量使用 #ifdef 區分 Unicode/ANSI、Console/GUI、DLL/EXE 等情境,同一檔案透過巨集產生 wcrt0.c、wincrt0.c、wwincrt0.c 等多種入口常式。

關鍵啟示

  1. main 並非真正入口:作業系統載入 EXE 後,先跳轉至 mainCRTStartup,完成 CRT 初始化後才呼叫 main。
  2. CRT 初始化不可省略:若直接將入口設為 main(略過 mainCRTStartup),printf 等函式在呼叫 _heap_alloc_base 時會因堆積未初始化而崩潰(下一篇將實測)。
  3. 原始碼面前,了無秘密:微軟提供完整 CRT 原始碼,善用「搜尋符號 → 定位檔案 → 閱讀邏輯」的流程,即可窺見底層運作全貌。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved