C和C 中呼叫約定和程式設計模式的區別

2021-08-20 11:28:49 字數 3256 閱讀 2390

1、呼叫約定

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

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

__cdecl呼叫約定僅在輸出函式名前加上乙個下劃線字首,格式為_functionname。 

__fastcall呼叫約定在輸出函式名前加上乙個「@」符號,後面也是乙個「@」符號和其引數的位元組數,格式@functionname@number。

它們均不改變輸出函式名中的字元大小寫,這和pascal呼叫約定不同,pascal約定輸出的函式名無任何修飾且全部大寫。 

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

__stdcall呼叫約定:

1、以「?」標識函式名的開始,後跟函式名;

2、函式名後面以「@@yg」標識參數列的開始,後跟參數列;

3、參數列以代號表示:

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」代表一次重複;

4、參數列的第一項為該函式的返回值型別,其後依次為引數的資料型別,指標標識在其所指資料型別前; 

5、參數列後以「@z」標識整個名字的結束,如果該函式無引數,則以「z」標識結束。

其格式為「?functionname@@yg*****@z」或「?functionname@@yg*xz」,例如 

int test1-----「?test1@@yghpadk@z」 

void test2-----「?test2@@ygxxz」

__cdecl呼叫約定:

規則同上面的_stdcall呼叫約定,只是參數列的開始標識由上面的「@@yg」變為「@@ya」。

__fastcall呼叫約定:

規則同上面的_stdcall呼叫約定,只是參數列的開始標識由上面的「@@yg」變為「@@yi」。

2、呼叫約定

呼叫約定(calling convention)是指在程式語言中為了實現函式呼叫而建立的一種協議。這種協議規定了該語言的函式中的引數傳送方式、引數是否可變和由誰來處理堆疊等問題。不同的語言定義了不同的呼叫約定。

在c++中,為了允許操作符過載和函式過載,c++編譯器往往按照某種規則改寫每乙個入口點的符號名,以便允許同乙個名字(具有不同的引數型別或者是不同的作用域)有多個用法,而不會打破現有的基於c的鏈結器。這項技術通常被稱為名稱改編(name mangling)或者名稱修飾(name decoration)。許多c++編譯器廠商選擇了自己的名稱修飾方案。

因此,為了使其它語言編寫的模組(如visual basic應用程式、pascal或fortran的應用程式等)可以呼叫c/c++編寫的dll的函式,必須使用正確的呼叫約定來匯出函式,並且不要讓編譯器對要匯出的函式進行任何名稱修飾。

呼叫約定用來:(一)處理決定函式引數傳送時入棧和(二)出棧的順序(由呼叫者還是被呼叫者把引數彈出棧),以及(三)編譯器用來識別函式名稱的名稱修飾約定等問題。

1、__cdecl

__cdecl是c/c++和mfc程式預設使用的呼叫約定,也可以在函式宣告時加上__cdecl關鍵字來手工指定。採用__cdecl約定時,函式引數按照從右到左的順序入棧,並且由呼叫函式者把引數彈出棧以清理堆疊。因此,實現可變引數的函式只能使用該呼叫約定。

由於每乙個使用__cdecl約定的函式都要包含清理堆疊的**,所以產生的可執行檔案大小會比較大。__cdecl可以寫成_cdecl。

2、__stdcall

__stdcall呼叫約定用於呼叫win32 api函式。

採用__stdcal約定時,函式引數按照從右到左的順序入棧,被呼叫的函式在返回前清理傳送引數的棧,函式引數個數固定。

由於函式體本身知道傳進來的引數個數,因此被呼叫的函式可以在返回前用一條ret n指令直接清理傳遞引數的堆疊。__stdcall可以寫成_stdcall。

3、__fastcall

__fastcall約定用於對效能要求非常高的場合。__fastcall約定將函式的從左邊開始的兩個大小不大於4個位元組(dword)的引數分別放在ecx和edx暫存器,其餘的引數仍舊自右向左壓棧傳送,被呼叫的函式在返回前清理傳送引數的堆疊。__fastcall可以寫成_fastcall。

關鍵字__cdecl、__stdcall和__fastcall可以直接加在要輸出的函式前,也可以在編譯環境的setting...->c/c++->code generation項選擇。

它們對應的命令列引數分別為/gd、/gz和/gr。

預設狀態為/gd,即__cdecl。當加在輸出函式前的關鍵字與編譯環境中的選擇不同時,直接加在輸出函式前的關鍵字有效。

3、_stdcall與_cdecl呼叫約定對比

在「windef.h」標頭檔案中可找到:

#define callback __stdcall

#define winapi __stdcall

#define winapiv __cdecl

#define apientry winapi

#define apiprivate __stdcall

#define pascal __stdcall

#define cdecl _cdecl

#ifndef cdecl#define cdecl _cdecl

#endif

複製**

幾乎我們寫的每乙個windows api函式都是__stdcall型別的,為什麼?

首先,我們談一下兩者之間的區別:windows的函式呼叫時需要用到棧(stack,一種先入後出的儲存結構)。當函式呼叫完成後,棧需要清除,這裡就是問題的關鍵,如何清除?如果我們的函式使用了__cdecl,那麼棧的清除工作是由呼叫者,用com的術語來講就是客戶來完成的。這樣帶來了乙個棘手的問題,不同的編譯器產生棧的方式不盡相同,那麼呼叫者能否正常的完成清除工作呢?答案是不能。如果使用__stdcall,上面的問題就解決了,函式自己解決清除工作。所以,在跨(開發)平台的呼叫中,我們都使用__stdcall(雖然有時是以winapi的樣子出現)。那麼為什麼還需要_cdecl呢?當我們遇到這樣的函式如fprintf()它的引數是可變的,不定長的,被呼叫者事先無法知道引數的長度,事後的清除工作也無法正常的進行,因此,這種情況我們只能使用_cdecl。

C 呼叫約定和名字約定

c 呼叫約定和名字約定 呼叫約定 cdecl fastcall與 stdcall,三者都是呼叫約定 calling convention 它決定以下內容 1 函式引數的壓棧順序,2 由呼叫者還是被呼叫者把引數彈出棧,3 以及產生函式修飾名的方法。1 stdcall呼叫約定 函式的引數自右向左通過棧傳...

C 呼叫約定和名字約定

呼叫約定是指程式在函式呼叫時傳遞引數和獲取返回值所採用的方法 通過暫存器 或通過棧 或者是兩者的混合。用於指定calling convention的修飾符主要有 cdecl,stdcall,fastcall等。呼叫約定可以通過工程設定 setting.c c advanced callingconv...

C 函式的呼叫約定

一 c c 函式的呼叫約定 預設使用 cdecl 1 cdecl c標準呼叫約定 2 stdcall windows標準呼叫約定 3 fastcall 快速呼叫約定 4 thiscall 類成員方法的呼叫約定 約定了 1 符號生成規則 列如 int sum int,int 1 sum yahhh z...