函式呼叫約定

2021-07-02 13:36:47 字數 1471 閱讀 9994

最近在看《windows程式設計》一書,在書中看到使用windows函式的時候,要在函式前面加上winapi這樣乙個關鍵字。winapi 是在windef.h中定義的,其定義如下

#define winapi __stdcall
其中__stdcall是一種函式呼叫的約定。

首先,這裡要清楚的第乙個問題是:什麼是函式呼叫的約定?

通過在網上搜尋,好搜百科給出了如下的定義:

函式呼叫約定,是指當乙個函式被呼叫時,函式的引數會傳遞給被呼叫的函式和返回值會被返回給呼叫函式。函式的呼叫約定就是描述引數是怎麼傳遞和由誰平衡堆疊的,當然還有返回值。

其中常用的函式約定有三種型別,分別是:

__pascal,

__stdcall,

__cdecl,

他們之間的區別如下表所示:

引數傳遞順序

誰負責清理引數占用的堆疊

__pascal

從左到有

呼叫者__stdcall

從右到左

被調函式

__cdecl

從右到左

呼叫者

呼叫函式的**和被呼叫函式必須採用相同的函式呼叫約定,程式才能正常執行。在windows上,__cdecl是c/c++程式的預設函式呼叫約定。

在有的cpu上,編譯器會用暫存器傳遞引數,函式使用的堆疊由被呼叫函式分配和釋放。這種呼叫約定在行為上和__cdecl有乙個共同點:實參和形引數目不符不會導致堆疊錯誤。

不過,即使用暫存器傳遞引數,編譯器在進入函式時,還是會將暫存器裡的引數存入堆疊指定的位置。引數和區域性變數一樣應該在堆疊中有一席之地。引數可以被理解為由呼叫函式指定的區域性變數。

其中,vc預設使用__cdecl。所以如果需要使用__stdcall,可採用兩種方法:

(1)可以在函式名前手工新增,只對單一函式有效

(2)直接修改工程屬性(c/c++ > advanced > calling convention)來一次性配置所有的函式

__cdecl可實現變長引數列表

__stdcall產生的**更小

__cdecl的執行速度更快,這和內聯函式有點類似,**越多當然執行的越快

__cdecl主呼叫函式進行引數壓棧並且恢復堆疊

__stdcall主呼叫函式進行引數壓棧,被調函式恢復堆疊

所以如果使用__cdecl的函式多次呼叫同一函式,就產生多分恢復碼

乙份恢復碼只能將一種長度的參數列出棧,所以要對不同長度的參數列堆疊恢復,必須要有多分恢復碼,所以變長引數列表必須由主調函式恢復堆疊

__stdcall呼叫約定在輸出函式名前加上乙個下劃線字首,後面加上乙個'@'符號和其引數的位元組數,格式為:_functionname@number

__stdcall通常用於dll的建立(以支援多語言的呼叫),此外win32api函式皆用__stdcall,所以win32程式中的自定義函式也最好使用__stdcall

__cdecl非dll的console程式

函式呼叫約定

函式呼叫約定有多種,這裡簡單說一下 1 stdcall 呼叫約定相當於16位動態庫中經常使用的 pascal 呼叫約定。在32位的vc 5.0中pascal呼叫約定不再被支援 實際上它已被定義為 stdcall。除了 pascal外,fortran和 syscall也不被支援 取而代之的是 stdc...

函式呼叫約定

函式呼叫約定1.stdcall是pascal程式的預設呼叫方式,通常用於win32 api中,函式採用從右到左的壓棧方式,自己在退出時清空堆疊。vc將函式編譯後會在函式名前面加上下劃線字首,在函式名後加上 和引數的位元組數。2 c呼叫約定 即用 cdecl關鍵字說明 按從右至左的順序壓引數入棧,由呼...

函式呼叫約定

1.stdcall是pascal程式的預設呼叫方式,通常用於win32 api中,函式採用從右到左的壓棧方式,自己在退出時清空堆疊。vc將函式編譯後會在函式名前面加上下劃線字首,在函式名後加上 和引數的位元組數。2 c呼叫約定 即用 cdecl關鍵字說明 按從右至左的順序壓引數入棧,由呼叫者把引數彈...