欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語言函數(shù)調(diào)用約定和返回值詳情

 更新時間:2022年07月14日 15:40:41   作者:BugMaker-shen  
這篇文章主要介紹了C語言函數(shù)調(diào)用約定和返回值詳情,函數(shù)調(diào)用約定不同,會影響函數(shù)生成的符號名,函數(shù)入?yún)㈨樞?,形參?nèi)存的清理者,更多相關(guān)需要的小伙伴可以參考下文詳情介紹

 一、函數(shù)調(diào)用約定

  • _cdecl:C調(diào)用約定
  • _stdcall:Windows標準的調(diào)用約定
  • _fastcall:快速調(diào)用約定
  • _thiscall:C++的成員函數(shù)調(diào)用約定

以上的函數(shù)調(diào)用約定入?yún)⒍际菑挠蚁蜃?,只有PASCAL從左向右

函數(shù)調(diào)用約定不同,會影響函數(shù)生成的符號名,函數(shù)入?yún)㈨樞?,形參?nèi)存的清理者

1. 影響函數(shù)生成的符號名

在一個文件中寫_cdecl的函數(shù)聲明:

在另一個文件中寫_stdcall的函數(shù)定義:

我們編譯鏈接一下:

鏈接器找不到__cdecl sum這個函數(shù)調(diào)用的定義,將聲明的地方改成__stdcall就可以鏈接成功

2. 影響形參內(nèi)存的釋放者

_stdcall

形參內(nèi)存還是由調(diào)用方開辟

ret表示把棧頂元素的值(調(diào)用處下一條指令的地址)賦給PC寄存器,并出棧棧頂元素(修改esp)
ret 8表示在ret操作的基礎上,執(zhí)行執(zhí)行指令add esp, 8

_fastcall

可以看到在_fastcall調(diào)用約定中,call指令前面并沒有push操作,而是通過寄存器把實參傳遞到形參(沒有壓棧出棧,速度很快),實參在調(diào)用方棧幀上,形參在被調(diào)用方棧幀上

在_fastcall調(diào)用約定中,最多只能通過寄存器將最左邊8字節(jié)的實參帶給形參,多于8字節(jié)的實參還是通過push的方式帶給調(diào)用方的形參

我們給sum傳入三個參數(shù),看看是誰釋放形參內(nèi)存 :

這就很清楚了,一共3個參數(shù),左邊的2個參數(shù)通過寄存器傳遞不需要清理內(nèi)存,只有一個形參內(nèi)存需要釋放,所以顯示ret 4

對于sum函數(shù)的第一個局部變量temp,在_cdecl和_stdcall中都是通過ebp-4訪問的,形參是通過ebp正向偏移訪問,因為形參內(nèi)存在調(diào)用方的棧幀上

而在_fastcall中是通過寄存器把左邊的8字節(jié)實參帶給sum的形參,并存放在sum函數(shù)的棧幀上:

mov edx, dword ptr [ebp-8]
mov ecx, dword ptr [ebp-4]

所以對于sum函數(shù)的第一個局部變量temp,只能通過ebp-0Ch訪問

_thiscall

對參數(shù)個數(shù)不確定的,調(diào)用者清理堆棧,否則被調(diào)用者清理堆棧

二、函數(shù)的返回值

函數(shù)的返回值分為內(nèi)置類型(char、short、int、long、float、double等)、結(jié)構(gòu)體類型、union、enum等

1. 0 < 返回值 <= 4字節(jié)

通過eax寄存器帶出

2. 4字節(jié) < 返回值 <= 8字節(jié)

#include <stdio.h>

typedef struct  {
	int a;
	int b;
}Data;

Data sum(Data a, Data b) {
	Data temp = { 0 };
	temp.a = a.a + b.a;
	return temp;
}
int main() {
	Data a = { 10 }; 
	Data b = {20};  
	Data ret = { 0 }; 
	ret = sum(a, b);
	return 0;
}

可以看到,4字節(jié) < 返回值 <= 8字節(jié)時,通過eax和edx寄存器帶出

3. 返回值 > 8字節(jié)

#include <stdio.h>

typedef struct  {
	int a[20];
}Data;

Data sum(Data a, Data b) {
	Data temp = { 0 };
	temp.a[0] = a.a[0] + b.a[0];
	return temp;
}

int main() {
	Data a = { 10 };
	Data b = {20};
	Data ret = { 0 };
	ret = sum(a, b);
	return 0;
}

壓參數(shù)的時候,沒有使用push指令,因為寄存器不夠用,故使用了循環(huán)拷貝的方法,從實參的空間拷貝到形參的空間

產(chǎn)生臨時量有三個地方:函數(shù)調(diào)用前,函數(shù)調(diào)用時return的地方,函數(shù)調(diào)用完成時。在接收大于8字節(jié)返回值時,是在函數(shù)調(diào)用前產(chǎn)生臨時量,并把臨時量內(nèi)存的地址壓棧,而這個臨時量是用來接收返回值的

我們看到不僅僅壓棧了實參a、b,還壓棧了臨時量的地址,可以把sum函數(shù)簡單理解為如下形式:

Data sum(void* tmp_address, Data a, Data b);

我們看一下sum函數(shù)中return時的匯編指令是如何待會80字節(jié)的返回值的

最后通過eax把臨時量的地址帶出來,調(diào)用函數(shù)就可以通過eax拿到sum函數(shù)的返回值了

如果臨時量在函數(shù)調(diào)用前產(chǎn)生,那被調(diào)用函數(shù)返回的時候,肯定是通過ebp+8訪問臨時量并寫入返回值。因為ebp指向的空間保存了調(diào)用函數(shù)的棧底地址,ebp+4指向的空間保存了call指令下一條指令的地址,ebp+8指向最后一個壓棧的實參,即用于帶出返回值的臨時量的地址

返回方式:

  • 返回值空間在[1,4],用eax寄存器
  • 返回值空間在[5,8],用eax、edx寄存器
  • 返回值空間大于8字節(jié)時,函數(shù)調(diào)用前產(chǎn)生臨時量用于存儲返回值,并把這個臨時量的地址作為最后一個實參壓棧,在被調(diào)用函數(shù)中通過ebp+8訪問該臨時量的地址

到此這篇關(guān)于C語言函數(shù)調(diào)用約定和返回值詳情的文章就介紹到這了,更多相關(guān)C函數(shù)調(diào)用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++中new和delete的介紹

    C++中new和delete的介紹

    今天小編就為大家分享一篇關(guān)于C++中new和delete的介紹,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • Matlab實現(xiàn)生成箭頭坐標軸詳解

    Matlab實現(xiàn)生成箭頭坐標軸詳解

    這篇文章主要介紹了如何利用Matlab實現(xiàn)生成箭頭坐標軸,為坐標軸增添箭頭,文中的示例代碼講解詳細,對我們學習Matlab有一定幫助,需要的可以參考一下
    2022-03-03
  • C語言中的結(jié)構(gòu)體快排算法

    C語言中的結(jié)構(gòu)體快排算法

    這篇文章主要介紹了C語言中的結(jié)構(gòu)體快排算法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • VC++實現(xiàn)View內(nèi)容保存為圖片的方法

    VC++實現(xiàn)View內(nèi)容保存為圖片的方法

    這篇文章主要介紹了VC++實現(xiàn)View內(nèi)容保存為圖片的方法,涉及VC++中Bitmap類的save方法相關(guān)使用技巧,需要的朋友可以參考下
    2016-08-08
  • 詳解Visual Studio 2019(VS2019) 基本操作

    詳解Visual Studio 2019(VS2019) 基本操作

    這篇文章主要介紹了詳解Visual Studio 2019(VS2019) 基本操作,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-03-03
  • 詳解C語言中accept()函數(shù)和shutdown()函數(shù)的使用

    詳解C語言中accept()函數(shù)和shutdown()函數(shù)的使用

    這篇文章主要介紹了詳解C語言中accept()函數(shù)和shutdown()函數(shù)的使用,用來操作socket相關(guān)的網(wǎng)絡通信,需要的朋友可以參考下
    2015-09-09
  • 理解C++編程中的std::function函數(shù)封裝

    理解C++編程中的std::function函數(shù)封裝

    這篇文章主要介紹了理解C++編程中的std::function函數(shù)封裝,std::function是C++11標準中的新特性,需要的朋友可以參考下
    2016-04-04
  • C++實現(xiàn)LeetCode(8.字符串轉(zhuǎn)為整數(shù))

    C++實現(xiàn)LeetCode(8.字符串轉(zhuǎn)為整數(shù))

    這篇文章主要介紹了C++實現(xiàn)LeetCode(8.字符串轉(zhuǎn)為整數(shù)),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • opencv3/C++繪制幾何圖形實例

    opencv3/C++繪制幾何圖形實例

    今天小編就為大家分享一篇opencv3/C++繪制幾何圖形實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12
  • C++中的delete不會將操作數(shù)置0

    C++中的delete不會將操作數(shù)置0

    這篇文章主要介紹了C++中的delete不會將操作數(shù)置0的相關(guān)資料,需要的朋友可以參考下
    2016-05-05

最新評論