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

C++函數調用約定詳解:stdcall、cdecl、fastcall、thiscall 與 naked call

     編輯:Java 相關知識

前言

在 C/C++ 程式設計中,函數調用約定決定了參數如何傳遞、堆疊由誰清理以及函數名稱如何修飾。理解這些約定對於混合語言編程、DLL 導出、以及底層除錯至關重要。本文將系統介紹五種常見的調用約定:stdcall、cdecl、fastcall、thiscall 以及較少見的 naked call。

堆疊與參數傳遞基礎

函數調用時,電腦通常使用堆疊來存儲傳遞給函數的參數。堆疊是一種「後進先出」的資料結構,擁有存儲區與堆疊頂指標。參數壓入堆疊的順序、以及函數返回後由呼叫者還是被呼叫者負責清理堆疊,構成了調用約定的核心差異。

1. stdcall(Pascal 調用約定)

語法: int _stdcall function(int a, int b);

  • 參數從右向左依次壓入堆疊
  • 由被呼叫函數自身清理堆疊
  • 函數名自動加前導底線,後接 @ 與參數總位元組數(如 _function@8)

組合語言示例:

push b      ; 先壓入第二個參數
push a      ; 再壓入第一個參數
call function
; 無需呼叫者清理堆疊

2. cdecl(C 預設調用約定)

語法: int function(int a, int b); 或 int _cdecl function(int a, int b);

  • 參數從右向左依次壓入堆疊
  • 由呼叫者清理堆疊
  • 函數名自動加前導底線(如 _function)

因為由呼叫者清理堆疊,cdecl 允許函數參數個數不固定(如 printf),這是 C 語言的一大特性。

push b
push a
call function
add esp, 8  ; 呼叫者清理堆疊

3. fastcall(快速調用約定)

語法: int _fastcall function(int a, int b);

  • 前兩個 DWORD 參數分別通過 ECX、EDX 寄存器傳遞
  • 其餘參數從右向左壓入堆疊
  • 由被呼叫函數清理堆疊
  • 函數名修飾規則同 stdcall(如 @function@8)

4. thiscall(C++ 成員函數預設約定)

thiscall 無法顯式指定,專用於 C++ 類成員函數。因為成員函數隱含 this 指標,故需特殊處理:

  • 參數從右向左壓入堆疊
  • 若參數個數固定,this 通過 ECX 傳遞;若不固定,this 在所有參數壓入後壓入堆疊
  • 參數固定時由函數自身清理堆疊(類似 stdcall),不固定時由呼叫者清理(類似 cdecl)

5. naked call

極少見的調用約定,高級語言中罕用。編譯器不產生序言/結語代碼,完全由程式設計師以組合語言控制堆疊幀,僅用於極度優化或特殊系統級程式碼。

函數名稱修飾規則補充

C 編譯器修飾

  • __stdcall:_function@參數位元組數
  • __cdecl:_function
  • __fastcall:@function@參數位元組數

C++ 編譯器修飾(Name Mangling)

C++ 為支援多載,編碼更複雜,以 ? 開頭,後接函數名、@@、呼叫約定標識(YG=stdcall, YA=cdecl, YI=fastcall)、參數類型編碼、以 @Z 結尾。例如:
int Test(char*, unsigned long) → ?Test@@YGHPADK@Z

總結

約定參數順序堆疊清理典型用途
stdcall右→左被呼叫者Win32 API、COM
cdecl右→左呼叫者C/C++ 預設、可變參數
fastcall前兩個用寄存器被呼叫者效能關鍵路徑
thiscall右→左視參數固定性C++ 非靜態成員函數

聲明與實作的調用約定必須一致,否則會導致堆疊損壞、程式崩潰或難以診斷的錯誤。跨模組(DLL/EXE)介面建議統一使用 stdcall 或 cdecl 並顯式標註。

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