c++:函數堆棧調用(附加相關面經)

一、什麼是棧以及特點?

由編譯器自動分配和釋放,操作方式類似於數據結構中的棧。棧用於維護函數調用的上下文,離開了棧函數調用就沒法實現。 “先進後出”

在計算機系統中,棧被定義爲一個特殊的容器,用戶可以將數據壓入棧中,也可以將已經壓棧的數據出棧;棧總是從高地址指向低地址,所以壓棧操作使得棧增大,出棧使得棧減小;棧頂由稱esp的寄存器進行定位,棧底由稱爲ebp的寄存器進行定位,壓棧操作使得棧頂的地址減小,出棧的操使棧頂地址增大;

二、棧的作用?
棧保存了一個函數調用所需要的維護信息,這常常被稱爲堆棧幀;堆棧幀的一般包括:

  1. 函數的返回地址和參數;
  2. 臨時變量:包括函數的非靜態局部變量以及編譯器自動生成的其他臨時變量;
  3. 保存的上下文:包括在函數調用前後需要保持不變的寄存器;

三、函數具體的堆棧調用

Main(調用方)函數中:
入棧:

  1. 壓入調用main函數的函數maincrtstartup ()函數的棧底指針;
  2.     開闢main函數的棧幀空間;
  3.     壓入形參以及調用函數;
  4.     壓入回退到調用方時,被調用方的下一條指令的地址;

清棧:

  1. 清理形參變量地址;
  2. Sum(被調用方)函數中:

入棧:

  1. 壓入調用sum函數的main函數的棧底指針;
  2.     開闢sum函數棧幀空間並且初始化0xCCCCCCCC;
  3.     壓入實參;

退棧:

  1. 清理sum函數的棧幀;
  2.     回退棧底指針;
  3.     返回調用方棧幀後下一條指令;

下面是完整的代碼演示:

#include<stdio.h>

int  sum(int a,int b)
{
	int tmp = 0;
	tmp  = a+b;
	return tmp;
}
int main ()
{
	int a =10;
	int b =20;
	int ret = 0;
		ret = sum(a,b);
		printf("ret = %d\n",ret);
}

uploading.gif正在上傳…重新上傳取消uploading.gif轉存失敗重新上傳取消
uploading.gif轉存失敗重新上傳取消uploading.gif正在上傳…重新上傳取消uploading.gif轉存失敗重新上傳取消

總結:

1、    壓入實參 自左向右
2、    壓下一行指令地址
3、    壓調用方函數的棧底指針
4、    跳轉到被調用方的棧幀
5、    開闢被調用方所需的棧空間

 

四、調用約定

 

  1. _cdecl C標準調用約定        (_cdecl  調用方開闢 調用方清理)
  2. _stdcall  windows標準調用約定(_stdcall  調用方開闢 被調用方清理)
  3. _fastcall  快速調用約定(fastcall  前兩個實參調用不開闢形參內存,第三個參數起)
  4. _thiscall 類成員方法調用約定

1、 函數的符號生成
2、 實參的入棧順序
3、 形參的開闢和清理

相關面經:

1.返回值如何帶出?

①如果  【函數的返回值<=4個字節】,則返回值通過寄存器eax帶回。

②如果  【4<函數的返回值<=8個字節】,則返回值通過兩個寄存器eax和edx帶回。

③如果  【函數的返回值>8個字節】,則返回值通過產生的臨時量帶回。

2.形參開闢內存嗎?由誰開闢?

形參開闢內存,由調用方開闢

3.形參的入棧順序?

形參的入棧順序爲從右至左

4.被調用方結束後如何知道回退到調用方棧幀上?

通過將調用方函數的棧底的地址壓入被調用方函數的棧底實現被調用函數結束後回退到調用方函數棧幀上。

5.函數調用完成如何知道執行下一行指令?

在將調用方函數棧底的地址壓入被調用方函數棧底前先將調用方的call指令下一行指令的地址壓棧實現函數調用完成後知道執行下一行指令的地址。

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章