C 呼叫約束

2022-06-04 12:48:11 字數 2948 閱讀 2149

1、要求

宣告定義處呼叫約定必須相同

int __stdcall add(int a, int b);

int __stdcall add(int a, int b)

return a + b;

2、函式呼叫過程

假設:a為呼叫者,b為被調者;a;

函式呼叫過程可以這麼描述:

(1)先將呼叫者(

a)的堆疊的基址(

ebp)入棧,以儲存之前任務的資訊。

(2)然後將呼叫者(

a)的棧頂指標(

esp)的值賦給

ebp,作為新的基址(即被呼叫者

b的棧底)。

(3)然後在這個基址(被呼叫者

b的棧底)上開闢(一般用

sub指令)相應的空間用作被呼叫者

b的棧空間。

(4)函式

b返回後,從當前棧幀的

ebp即恢復為呼叫者

a的棧頂(

esp),使棧頂恢復函式

b被呼叫前的位置;然後呼叫者

a再從恢復後的棧頂可彈出之前的

ebp值(可以這麼做是因為這個值在函式呼叫前一步被壓入堆疊)。這樣,

ebp和

esp就都恢復了呼叫函式

b前的位置,也就是棧恢復函式

b呼叫前的狀態。

這個過程在at&t彙編中通過兩條指令完成,即:

__cdecl 是

c declaration

的縮寫,表示

c 和

c++

預設的函式呼叫約定。是

c/c++

和mfcx

的預設呼叫約定。

按從右至左的順序壓引數入棧。a(b,c,d);先進d->c->b

由呼叫者把引數彈出棧。切記:對於傳送引數的記憶體棧是由呼叫者來維護的,返回值在eax中。因此對於像

printf

這樣可變引數的函式必須用這種約定。

編譯器在編譯的時候對這種呼叫規則的函式生成修飾名的時候,在輸出函式名前加上乙個下劃線字首,格式為_function。如函式

int add(int a, int b)

的修飾名是

_add

4、__stdcall

__stdcall是

standard call

的縮寫,是

c++的標準呼叫方式

,當然這是微軟定義的標準,

__stdcall

通常用於

win32 api中(

可檢視winapi

的定義)

。按從右至左的順序壓引數入棧。

由被呼叫者把引數彈出棧。切記:函式自己在退出時清空堆疊,返回值在eax中。

__stdcall呼叫約定在輸出函式名前加上乙個下劃線字首,後面加上乙個「

@」符號和其引數的位元組數,格式為

_function@number

。如函式

int sub(int a, int b)

的修飾名是

_sub@8

5、__fastcall

__fastcall呼叫的主要特點就是快,因為它是通過暫存器來傳送引數的。

實際上__fastcall用

ecx和

edx傳送前兩個

dword

或更小的引數,剩下的引數仍自右向左壓棧傳送,被呼叫的函式在返回前清理傳送引數的記憶體棧。

__fastcall呼叫約定在輸出函式名前加上乙個「

@」符號,後面也是乙個「

@」符號和其引數的位元組數,格式為

@function@number,

如double multi(double a, double b)

的修飾名是

@multi@16

。__fastcall和

__stdcall

很象,唯一差別就是頭兩個引數通過暫存器傳送。注意通過暫存器傳送的兩個引數是從左向右的,即第

1個引數進

ecx,第2個進

edx,其他引數是從右向左的入棧,返回仍然通過

eax。

6、__pascal

這種規則

從左向右傳遞引數,通過eax返回,堆疊由被呼叫者清除

7、__thiscall

__thiscall是

c++類成員函式預設的呼叫約定,但它沒有顯示的宣告形式。因為在

c++類中,成員函式呼叫還有乙個

this

指標引數,因此必須特殊處理,

thiscall

呼叫約定的特點:

引數入棧:引數從右向左入棧

his指標入棧:如果引數個數確定,

this

指標通過

ecx傳遞給被呼叫者;如果引數個數不確定,

this

指標在所有引數壓棧後被壓入棧。

棧恢復:對引數個數不定的,呼叫者清理棧,否則函式自己清理棧。

8、總結

呼叫規則

入棧順序

清棧責任

__cdecl

從右到左

呼叫者__stdcall

從右到左

被呼叫者

__fastcall

從右到左(先 edx、ecx,再到堆疊)

被呼叫者

__pascal

從左到右

被呼叫者

c 呼叫lua,lua呼叫c

建立工程 引用lua的動態庫和工程專案的配置資訊 結合 main.lua指令碼檔案 print lua呼叫c lua呼叫c 結合部分 c 向lua堆疊寫東西 通過lua堆疊 lua通過lua全域性標量獲取返回lua堆疊再到c lua傳遞數字給c cgivelua wangcheng 22,1 lua...

c 呼叫c和c呼叫c

c 的設計是相容c的,但是呼叫的時候還是需要遵循規則 1 包含標頭檔案 extern c 2 宣告呼叫的函式 extern c 為什麼要加extern c 1 c 語言支援函式過載,c語言不支援函式過載。2 函式被c 編譯後在庫中的名字與c語言的不同。void add int x,int y 該函式...

c 泛型約束

在定義泛型類時,可以對客戶端 能夠在例項化類時用於型別引數的型別種類施加限制。如果客戶端 嘗試使用某個約束所不允許的型別來例項化類,則會產生編譯時錯誤。這些限制稱為約束。約束是使用 where 上下文關鍵字指定的。下表列出了六種型別的約束 約束說明 t struct 型別引數必須是值型別。可以指定除...