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

C/C++ 函數呼叫慣例完全解析:__stdcall、__cdecl、__fastcall、thiscall 與名稱修飾

     編輯:VC 教學

什麼是呼叫慣例?

呼叫慣例規範函數呼叫時:參數壓堆順序、堆疊平衡由誰負責、暫存器使用、函數名稱修飾規則。決定了呼叫者與被呼叫者的二進位介面契約,跨語言、跨模組(DLL)互呼時必須一致。

五大主流呼叫慣例對比

慣例關鍵字參數壓堆順序堆疊清理者名稱修飾 (VC++)典型用途
__stdcall__stdcall / WINAPI右至左被呼叫者_Func@NWin32 API、COM、DLL 導出
__cdecl__cdecl (預設)右至左呼叫者_FuncC/C++ 預設、可變參數函數
__fastcall__fastcall前兩個 DWORD 用 ECX/EDX,其餘右至左壓堆被呼叫者@Func@N效能敏感路徑、Borland 編譯器預設
thiscall(隱含,非關鍵字)this 在 ECX,其餘右至左壓堆被呼叫者依編譯器而異C++ 非靜態成員函數
naked call__declspec(naked)自定自定無修飾裸機程式、中斷服務、手寫序言/結語

關鍵細節深度解析

1. __stdcall (WINAPI)

  • Windows API 統一採用,確保 DLL 導出函數二進位相容。
  • 函數結尾用 RET N 自動彈出參數,呼叫端無須調整 ESP。
  • 名稱修飾:_FunctionName@參數總位元組數(如 _MyFunc@12)。
  • 巨集 WINAPI 在 Windows.h 定義為 __stdcall,建議所有 DLL 導出介面使用。

2. __cdecl (C/C++ 預設)

  • 支援可變參數(如 printf),因呼叫者知道壓了多少參數。
  • 每個呼叫點都產生清理堆疊程式碼,執行檔體積較大。
  • 名稱修飾:僅加前綴底線 _FunctionName。
  • MFC 預設亦為 __cdecl。

3. __fastcall

  • 前兩個 32 位元參數放入 ECX、EDX,減少記憶體存取。
  • VC++ 名稱修飾:@FunctionName@N。
  • Borland 編譯器預設即為 __fastcall(關鍵字 __msfastcall 才對應 VC 風格)。

4. thiscall (C++ 成員函數專用)

  • this 指標固定放在 ECX,參數右至左壓堆。
  • 非關鍵字,程式設計師無法直接指定。
  • 虛函數呼叫經由 vtable 間接跳轉,慣例相同。

5. 名稱修飾與 extern "C"

C++ 支援函數多載,編譯器會將函數簽章(類別、參數型別、呼叫慣例、回傳型別)編碼進修飾名稱。若需提供 C 相容介面(如 DLL 導出給 C 語言呼叫),必須加上 extern "C" 關閉修飾:

extern "C" __declspec(dllexport) void __stdcall MyAPI(int a);

此時匯出名稱即為原始 MyAPI,無修飾、無多載。

專案設定與命令列選項

  • /Gd:預設 __cdecl
  • /Gz:預設 __stdcall
  • /Gr:預設 __fastcall
  • 函數前加關鍵字優先級高於專案預設。

實戰建議

  1. 撰寫 DLL 導出介面:統一用 extern "C" __stdcall(或 WINAPI),並提供 .def 檔或 __declspec(dllexport)。
  2. 跨語言呼叫(C# P/Invoke、Python ctypes):宣告為 StdCall,參數型別對應 int→Int32、char*→StringBuilder/c_char_p。
  3. 效能熱點函數:嘗試 __fastcall,但需測量實際提升(現代編譯器優化極強,差異常微乎其微)。
  4. 避免在專案中混用不同預設慣例,統一專案設定或顯式標註每個函數。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved