函式呼叫的三種方式 __cdecl、__stdcall、__fastcall
__cdecl、__stdcall、__fastcall是C/C++裡中經常見到的三種函式呼叫方式。
__cdecl是C/C++預設的呼叫方式
__stdcall是windows API函式的呼叫方式,只不過我們在標頭檔案裡檢視這些API的宣告的時候是用了WINAPI的巨集進行代替了,而這個巨集其實就是__stdcall了。
函式的呼叫過程是通過函式棧幀的不斷變化實現的:
函式的呼叫,涉及引數傳遞,返回值傳遞,呼叫後返回,這都是通過棧的變化來實現的,對於三種呼叫約定而言:
__cdecl:
C/C++預設方式,引數從右向左入棧,主調函式負責棧平衡。
__stdcall:
windows API預設方式,引數從右向左入棧,被調函式負責棧平衡。
__fastcall:
快速呼叫方式。所謂快速,這種方式選擇將引數優先從暫存器傳入(ECX和EDX),剩下的引數再從右向左從棧傳入。因為棧是位於記憶體的區域,而暫存器位於CPU內,故存取方式快於記憶體,故其名曰“__fastcall”。
#include <stdio.h>
class Point
{
public:
Point(int x, int y)
{
nx = x;
ny = y;
nTest = nx + ny;
}
~Point(){}
int nx;
int ny;
int nTest;
};
void __cdecl Fun1(int x, int y)
{
Point pt(0, 0);
pt.nx = x;
pt.ny = y;
}
void __fastcall Fun2(int x, int y)
{
Point pt(0, 0);
pt.nx = x;
pt.ny = y;
}
void __stdcall Fun3(int x, int y)
{
Point pt(0, 0);
pt.nx = x;
pt.ny = y;
}
int main()
{
Fun1(2, 5);//__cdecl
Fun2(2, 5);//__fastcall
Fun3(2, 5);//__stdcall
return 0;
}
先打斷點,進行反彙編
__cdecl按照引數從右向左的方式進入棧區,注意Fun1()和Fun3()的區別,Fun1()在call Fun1()之後執行了add esp,8。這一操作正是我們前面所說的進行棧的平衡。
呼叫函式之前連續進行了兩次push操作將函式所需的實參5和2先後壓入了棧區,呼叫完成後,我們需要恢復呼叫前的狀態,則需調整棧頂指標esp的位置,這一工作由誰來完成就決定了兩種函式呼叫方式__cdecl(主調函式完成)和__stdcall(被調函式完成)的區別。上圖我們看到了__cdecl中由主調函式完成了,那麼__stdcall呢,在被調函式Fun3()中,轉向被調函式結尾處的程式碼,我們看到了這一句:
fun1()結尾處
這個ret指令後面跟沒跟值就決定了函式返回是棧指標ESP需要增加的量。這樣,不需要主調函式再呼叫add指令為ESP操作平衡棧區,節約了程式的開銷,一條指令開銷小,如果十萬百萬個這樣的呼叫,這個開銷就明顯了。
__fastcall,如前面圖看到的呼叫時並未使用push指令向棧裡傳引數,而是使用了
兩條指令。這樣直接將引數傳入暫存器,被調函式在執行的時候直接從暫存器取值即可,省去了從棧裡取出來給暫存器,再從暫存器取出來放入記憶體。
ecx暫存器經常作為計數和C++裡this指標的傳遞媒介。ecx做計數器時,需要將ecx中儲存的實參先壓入棧區,計數操作完成後再pop出來。如此一來,這個fastcall倒顯得不那麼fast了。
相關文章
- 函式呼叫方式 FAR PASCAL,__cdecl,_stdcall,__pasc函式
- __stdcall,__cdecl,__fastcall的區別AST
- WIN32程式設計必知:__stdcall,__cdecl,__fastcall,thiscall,naked callWin32程式設計AST
- 幾種函式呼叫方式函式
- JS的五種函式呼叫方式JS函式
- react中三種函式呼叫方法總結React函式
- php 遞迴函式的三種實現方式PHP遞迴函式
- 函式的呼叫方式和引數函式
- JavaScript中七種函式呼叫方式及對應 this 的含義JavaScript函式
- go 陣列傳遞給函式三種方式Go陣列函式
- js函式使用的幾種方式JS函式
- JavaScript 函式的兩種宣告方式JavaScript函式
- js裡函式呼叫的四種模式JS函式模式
- javascript呼叫函式的方式簡單介紹JavaScript函式
- shell中呼叫shell的三種方式&並行shell並行
- JS中建立函式的幾種方式JS函式
- 開窗函式的另外一種方式函式
- javascript匿名函式常用呼叫方式介紹JavaScript函式
- javascript函式呼叫方式簡單介紹JavaScript函式
- Vue元件開發實錄:元件的三種呼叫方式Vue元件
- 建構函式,拷貝賦值函式的N種呼叫情況函式賦值
- 一種WebService的呼叫方式Web
- javascript兩種宣告函式方式的區別JavaScript函式
- Python透過函式名呼叫函式的幾種場景Python函式
- 使用C#建立webservice及三種呼叫方式 (轉)C#Web
- Android中js呼叫java本地方法的三種方式AndroidJSJava
- html樣式表三種引入方式HTML
- 外部函式的呼叫函式
- jmeter學習指南之Beanshell 呼叫 java 程式碼的三種方式JMeterBeanJava
- 函式你必須知道的三種角色?函式
- 三種方法實現strlen函式函式
- 三欄式佈局的幾種實現方式
- PHP 三種方式實現鏈式操作PHP
- Js基礎知識4-函式的三種建立、四種呼叫(及關於new function()的解釋)JS函式Function
- JS中函式內套函式的呼叫JS函式
- Javascript中兩種方式定義函式的區別JavaScript函式
- java中寫建構函式的另外一種方式Java函式
- Visual C++中函式呼叫方式淺探 (轉)C++函式