三種函式呼叫約定

2021-09-17 05:42:19 字數 1497 閱讀 2883

__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」。

下面從例項來認識一下這三種呼叫約定。先來看乙個簡單的不能再簡單的程式了:

三個函式的內容都是一樣的,不同的是使用了三種呼叫的方式。我們先來看看在main函式呼叫三個函式的時候的彙編**:

按照上面說的那樣,__cdecl按照引數從右向左的方式進入棧區,注意fun1()和fun3()的區別,fun1()在call fun1()之後執行了add esp,8。這一操作正是我們前面所說的進行棧的平衡。呼叫函式之前連續進行了兩次push操作將函式所需的實參5和2先後壓入了棧區,呼叫完成後,我們需要恢復呼叫前的狀態,則需調整棧頂指標esp的位置,這一工作由誰來完成就決定了兩種函式呼叫方式__cdecl(主調函式完成)和__stdcall(被調函式完成)的產生。上圖我們看到了__cdecl中由主調函式完成了,那麼__stdcall呢,在被調函式fun3()中,轉向被調函式結尾處的**,我們看到了這一句:

那麼fun1()結尾處又是如何呢?

看到了吧,這個ret指令後面跟沒跟值就決定了函式返回是棧指標esp需要增加的量。這樣,不需要主調函式再呼叫add指令為esp操作平衡棧區,節約了程式的開銷,一條指令開銷小,如果十萬百萬個這樣的呼叫,這個開銷就明顯了。

說完了__cdecl和__stdcall,再來看看__fastcall,如前面圖看到的呼叫時並未使用push指令向棧裡傳引數,而是使用了

mov  edx, 5

mov ecx, 2

兩條指令。這樣直接將引數傳入暫存器,被調函式在執行的時候直接從暫存器取值即可,省去了從棧裡取出來給暫存器,再從暫存器取出來放入記憶體。

收藏

約定stdcall 函式呼叫的三種約定,你都清楚嗎

cdecl stdcall fastcall是c c 裡中經常見到的三種函式呼叫方式。其中 cdecl是c c 預設的呼叫方式,stdcall是windows api函式的呼叫方式,只不過我們在標頭檔案裡檢視這些api的宣告的時候是用了winapi的巨集進行代替了,而這個巨集其實就是 stdcall...

約定stdcall 函式呼叫的三種約定,你都清楚嗎

cdecl stdcall fastcall是c c 裡中經常見到的三種函式呼叫方式。其中 cdecl是c c 預設的呼叫方式,stdcall是windows api函式的呼叫方式,只不過我們在標頭檔案裡檢視這些api的宣告的時候是用了winapi的巨集進行代替了,而這個巨集其實就是 stdcall...

系統篇 小議三種函式呼叫約定

小議三種函式呼叫約定 cdecl stdcall fastcall 是c c 裡中經常見到的三種函式呼叫方式。其中 cdecl 是c c 預設的呼叫方式,stdcall 是windows api 函式的呼叫方式,只不過我們在標頭檔案裡檢視這些api 的宣告的時候是用了winapi 的巨集進行代替了,...