本章目錄
- 溫馨提示
- 開篇介紹
- 學前疑惑
- 學前準備
- 1. 環境選擇
- 2. 知識鋪墊
- 正文開始
- 1. 大致輪廓了解(源代碼及反匯編)
- 2. 函式堆疊幀的創建和銷毀總流程
- 3.函式堆疊幀的創建
- 3.1 main函式的創建(分解)
- 3.2 Add函式的創建(分解)
- 4.函式堆疊幀的銷毀
- 4.1 main函式的銷毀(分解)
- 5.1 Add函式的銷毀(簡潔)
- 5. 問題回答
- 全文結束
溫馨提示
大家好我是Cbiltps,在我的博客中如果有難以理解的句意,難以用文字表達的重點,我會有配圖,所以我的博客配圖非常重要!!!
你想更好并順利的學習函式堆疊幀章節,我強烈建議你看我寫的【C語言初階】除錯技巧的博客,會有什么效果?等你看了并學習本章后就會感受到!!!
更重要的一點,在分析流程的時候是根據反匯編語言一步一步的進行的,但是這個程序用文字不好解釋(非常繁多),于是我為了理解畫了很長時間的圖,所有的一切都在圖中展示!!!切記,切記!如果還不理解,請聯系我,我們可以打視頻等方式……
如果你對我感興趣請看我的第一篇博客!
開篇介紹
今天寫的是【C語言進階】的第二篇內容:函式堆疊幀,函式堆疊幀真的是修煉內功!
以前很多地方是講函式堆疊幀的,但是絕大多數同學是聽不懂的,后來就少講或者是不講;而且發現公司不愿意考這些東西了(考的少),
但是這個東西非常重要,如果你真的懂了這個東西,那真的是練成了神功!
學前疑惑
前期學習的時候,我們可能有很多困惑:
- 區域變數是如何創建的?
- 為什么區域變數的值是隨機值?
- 函式是如何傳參的?
- 函式傳參的順序是怎樣的?
- 形參和實參是什么關系?
- 函式呼叫是如何做的?
- 函式呼叫結束后是如何回傳的?
如果你想明白這些問題,等你學習完函式堆疊幀的創建和銷毀后就知道了,其實就是修煉了自己的內功,也能搞懂后期更多的知識!
學前準備
1. 環境選擇
在學習函式堆疊幀的時候,我使用的環境是 VS2013(VC6.0也是可以的,它對于函式堆疊幀的創建和銷毀的程序是足夠簡單的),不要使用太高級的編譯器,越高級的編譯器,越不容易學習和觀察(考慮各種問題,封裝更加復雜),
同時在不同的編譯器下,函式呼叫程序中堆疊幀的創建是略有差異的,具體細節取決于編譯器的實作,
2. 知識鋪墊
要想學習函式堆疊幀,就必須再給大家做一個小小的鋪墊:了解暫存器!
資料暫存器:
- eax
- ebx
- ecx
- edx
指標暫存器:
- ebp
- esp
而本章節的重點是后指標暫存器(ebp和esp),要想理解函式堆疊幀,就必須理解這兩個暫存器,
這兩個暫存器中存放的是地址,這兩個地址是用來維護函式堆疊幀的,
那ebp和esp是如何維護函式堆疊幀的呢?
正在呼叫哪個函式,esp和ebp維護的就是哪個函式的函式堆疊幀,esp和ebp之間的空間就是為這個函式開辟的空間,
正文開始
1. 大致輪廓了解(源代碼及反匯編)
本章節會用下面一段代碼舉例:
#include <stdio.h>
int Add(int x, int y)
{
int z = 0;
z = x + y;
return z;
}
int main()
{
int a = 10;
int b = 20;
int c = 0;
c = Add(a, b);
printf("%d\n", c);
return 0;
}
首先呼叫堆疊觀察:其實這個呼叫邏輯還是挺復雜的!

然后畫一個概念圖理解(堆疊區):

上面的決議只是一個大概的輪廓,但是具體是怎么做的呢?
我們需要轉到反匯編來探究:
int main()
{
000919F0 push ebp
000919F1 mov ebp,esp
000919F3 sub esp,0E4h
000919F9 push ebx
000919FA push esi
000919FB push edi
000919FC lea edi,[ebp-0E4h]
00091A02 mov ecx,39h
00091A07 mov eax,0CCCCCCCCh
00091A0C rep stos dword ptr es:[edi]
int a = 10;
00091A0E mov dword ptr [a],0Ah
int b = 20;
00091A15 mov dword ptr [b],14h
int c = 0;
00091A1C mov dword ptr [c],0
c = Add(a, b);
00091A23 mov eax,dword ptr [b]
00091A26 push eax
00091A27 mov ecx,dword ptr [a]
00091A2A push ecx
00091A2B call _Add (0911DBh)
00091A30 add esp,8
00091A33 mov dword ptr [c],eax
printf("%d\n", c);
00091A36 mov esi,esp
printf("%d\n", c);
00091A38 mov eax,dword ptr [c]
00091A3B push eax
00091A3C push 95858h
00091A41 call dword ptr ds:[99114h]
00091A47 add esp,8
00091A4A cmp esi,esp
00091A4C call __RTC_CheckEsp (091136h)
return 0;
00091A51 xor eax,eax
}
00091A53 pop edi
00091A54 pop esi
00091A55 pop ebx
00091A56 add esp,0E4h
00091A5C cmp ebp,esp
00091A5E call __RTC_CheckEsp (091136h)
00091A63 mov esp,ebp
00091A65 pop ebp
00091A66 ret
上面的代碼就是反匯編代碼,下面我們就開始學習吧!
2. 函式堆疊幀的創建和銷毀總流程

3.函式堆疊幀的創建
3.1 main函式的創建(分解)

3.2 Add函式的創建(分解)

4.函式堆疊幀的銷毀
4.1 main函式的銷毀(分解)

5.1 Add函式的銷毀(簡潔)
前面的部分和main函式的一樣,所以不做過多的介紹!

5. 問題回答
- 區域變數是如何創建的?
首先為函式分配堆疊幀空間,在堆疊幀空間初始化一部分的空間后,在堆疊幀中給區域變數分配空間,
- 為什么區域變數的值是隨機值?

在堆疊幀空間初始化一部分的空間,其實就是賦了很多的'C',這就是隨機值,
而以前列印出來看到的:燙燙燙燙燙燙燙燙燙燙燙燙…… 就是因為區域變數的值是隨機值,
- 函式是如何傳參的?
直接看圖:

- 函式傳參的順序是怎樣的?
其實還沒有呼叫函式的時候,已經從右向左 push ,
- 形參和實參是什么關系?
形參是實參的一分臨時拷貝,值相同,空間獨立,
改變形參,不會影響實參,
- 函式呼叫是如何做的?
理解上面的圖!不好解釋!
- 函式呼叫結束后是如何回傳的?
理解上面的圖!不好解釋!
全文結束
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/305511.html
標籤:其他
上一篇:STM32——直流電機PI調速
