最近在看《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關鍵字說明 按從右至左的順序壓引數入棧,由呼叫者把引數彈...