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

C 語言實現「建構函數」機制:GCC 與 MSVC 的異同解析

     編輯:關於C語言

物件導向語言的建構函數(Constructor)可在 main 執行前自動完成初始化。C 語言雖為程序導向,但透過編譯器擴展同樣能達到此目的——這對框架設計極為關鍵,能讓使用者免去手動呼叫初始化函數的麻煩。

為何需要 main 前初始化?

若在 main 內手動呼叫初始化,框架使用者必須記得調用順序,且難以強制執行。若能像 C++ 那樣靠全域物件建構自動跑初始化碼,框架體驗將大幅提升。

GCC:優雅的 __attribute__((constructor))

GCC 提供編譯器屬性,只需在函數宣告前加上:

void __attribute__((constructor)) my_init(void) {
    // 初始化碼會在 main 之前自動執行
}

多個建構函數依定義順序執行,支援優先級語法 __attribute__((constructor(101))) 控制順序。

MSVC:將函數指標塞進 .CRT$XCU 區段

MSVC 無類似屬性,須利用 #pragma section 將函數指標放入 CRT 初始化區段 .CRT$XCU:

#pragma section(".CRT$XCU", read)
__declspec(allocate(".CRT$XCU")) void (__cdecl *my_ctor)(void) = my_init;

連結器會依區段名排序(.CRT$XCA ~ .CRT$XCZ),依序呼叫區段內的函數指標,達到相同效果。

跨平台巨集封裝

為統一兩邊寫法,常見做法定義 __CONSTRCT(name, unique_id) 巨集:

#ifdef _MSC_VER
#define __CONSTRCT(a, b) \
  void __cdecl __##a##__##b##__init(void); \
  __declspec(allocate(".CRT$XCU")) \
  void (__cdecl * __ctor__##a##__##b##__init)(void) = __##a##__##b##__init;
#else
#define __CONSTRCT(a, b) __attribute__((constructor))
#endif

使用時:__CONSTRCT(mymodule, 001) void my_init() { ... } 即可跨平台編譯。

應用場景:輕量級單元測試框架

模仿 Google Test,利用建構函數自動註冊測試案例,main 只需呼叫 run_all_tests() 即可發現並執行所有測試,無需手動列舉。完整範例可參考筆者部落格:C 建構函數實現詳解。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved