函式呼叫方式 2

2021-06-20 16:07:51 字數 2771 閱讀 8670

在進行函式呼叫時,有幾種呼叫方法,主要有__cdecl,__stdcall,__fastcall,__thiscall

,__clrcall,naked call。它們決定以下內容:1)函式引數的壓棧順序,2)由呼叫者還是被呼叫者把引數彈出棧,3)以及產生函式修飾名的方法。

1、__stdcall呼叫約定:用於呼叫win32 api函式。函式的引數自右向左通過棧傳遞,除非引數是指標或引用,否則是按值傳遞。在主呼叫函式中負責壓棧,在被呼叫函式中負責彈出堆疊中的引數,並負責恢復堆疊。不能實現變參函式。採用這種呼叫方式的函式需要乙個函式原型。如果函式是可變引數的,則編譯器會將函式的呼叫方式改為__cdecl呼叫。

2、__cdecl呼叫約定:是c和c++程式的預設呼叫方式。函式引數的壓棧順序是從右到左,由主呼叫函式進行引數壓棧並且恢復堆疊。由於主呼叫函式管理堆疊,所以可以實現變參函式。由於每乙個呼叫它的函式都包含清空堆疊的**,所以產生的可執行檔案大小會比呼叫_stdcall函式的大。注意:對於可變引數的成員函式,始終使用__cdecl的轉換方式。

3、__fastcall呼叫約定:其呼叫的主要特點就是快,因為在盡可能的情況下,它是通過暫存器來傳送引數的(實際上,它用ecx和edx傳送前兩個雙字(dword)或更小的引數,剩下的引數仍舊自右向左壓棧傳送),被呼叫的函式在返回前清理傳送引數的記憶體棧。

4、__thiscall呼叫約定:應用於"c++"成員函式,並且是不採用可變引數的c++成員函式的預設呼叫方式。函式引數的壓棧順序是從右到左,被呼叫者清理堆疊,所以不能實現可變引數。在x86系統中,this指標存放於cx/ecx暫存器中,而不是棧中。使用__thiscall的原因之一是當成員函式的預設呼叫方式是__clrcall的時候,使用__thiscall可以使某個成員函式可以被本地**呼叫。

5、__clrcall呼叫約定:它與.net framework有關係,用於指定函式只能被託管**(managed code)呼叫。這樣編譯器就不會生成原生的入口點了。

6、naked call呼叫約定:這是vc裡一種給高階使用者使用的呼叫約定,它實際上就是沒有規範,使用者可以通過內嵌彙編來實現任意想要的呼叫約定。naked call不是型別修飾符,故必須和__declspec共同使用。

7、過時的呼叫約定:__pascal,__fortran和__syscall呼叫方式現在已不支援。可以用現今支援的函式呼叫方式配合合適的鏈結器選項來實現同樣的功能。windows.h現在支援winapi巨集,它可以為目標轉換成合適的呼叫方式。

備註:1、關鍵字__stdcall、__cdecl和__fastcall可以直接加在要輸出的函式前。它們對應的命令列引數分別為/gz、/gd和/gr。預設狀態為/gd,即__cdecl。

2、呼叫約定可以通過工程設定:如在vs2008中,project->properties->configuration properties->c/c++->advanced->calling convention。預設為__cdecl(/gd)。

函式名字修飾約定:

a、c編譯時函式名修飾約定規則:

1、__stdcall呼叫約定:在輸出函式名前加上乙個下劃線字首,後面加上乙個"@"符號和其引數的總位元組數(10進製),格式為,不進行大小寫轉換。如:void input(int &m,int &n),被修飾成:。

2、__cdecl呼叫約定:僅在輸出函式名前加上乙個下劃線字首,格式為_functionname,不進行大小寫轉換。

3、__fastcall呼叫約定:在輸出函式名前加上乙個"@"符號,後面也是乙個"@"符號和其引數的位元組數,格式為@functionname@number,不進行大小寫轉換。

b、c++編譯時函式名修飾約定規則:

1、__stdcall呼叫約定:以"標識參數列的開始,後跟參數列;參數列以代號表示:

x--void ,

d--char,

e--unsigned char,

f--short,

h--int,

i--unsigned int,

j--long,

k--unsigned long,

m--float,

n--double,

_n--bool,

pa--表示指標,後面的代號表明指標型別。如果相同型別的指標連續出現,以"0"代替,乙個"0"代表一次重複; 參數列的第一項為該函式的返回值型別,其後依次為引數的資料型別,指標標識在其所指資料型別之前;參數列後以"@z"標識整個名字的結束,如果該函式無引數,則以"xz"標識結束。

其格式為""或""。

如:int test1(char *var1,unsigned long),被修飾成:

void test2(),被修飾成:

2、__cdecl呼叫約定:規則同上面的__stdcall呼叫約定,只是參數列的開始標識由上面的"@@yg"變為"@@ya"。

3、__fastcall呼叫約定:規則同上面的__stdcall呼叫約定,只是參數列的開始標識由上面的"@@yg"變為"@@yi"。

注意:1、_beginthread需要__cdecl的執行緒函式位址,_beginthreadex和createthread需要__stdcall的執行緒函式位址。

2、一般win32的函式都是__stdcall。而且在windef.h中有如下的定義:

#define callback __stdcall

#define winapi __stdcall

3、對於extern "c" _declspec(dllexport) int __cdecl add(int a, int b);

修飾符的書寫順序應該為:

typedef int (__cdecl*funpointer)(int a, int b);

**:

函式呼叫方式

cdecl 是c declaration的縮寫,表示c語言預設的函式呼叫方法 所有引數從右到左依次入棧,這些引數由呼叫者清除,稱為手動清棧。被呼叫函式不需要求呼叫者傳遞多少引數,呼叫者傳遞過多或者過少的引數,甚至完全不同的引數都不會產生編譯階段的錯誤。stdcall 是standard call的縮...

函式呼叫方式

現代的程式語言的函式竟然有那麼多的呼叫方式。這些東西要完全理解還得通過彙編 才好理解。他們各自有自己的特點 其實這些呼叫方式的差別在主要在一下幾個方面 1.引數處理方式 傳遞順序,訪問 利用盞還是暫存器 2.函式的結尾處理方式 善後處理 如 棧的恢復由誰恢復?函式內恢復 還是呼叫後恢復 以下是理論 ...

函式呼叫方式

所謂的呼叫方式是指 在呼叫乙個函式時,約定的傳遞引數方式和平衡堆疊方式,例如 有乙個函式,它有兩個引數 xyz first,second 當我們使用stdcall呼叫方式時,也就是windows呼叫api的常見方式 又幾個函式例外 它的呼叫方式如下 x1 push second x2 push fi...