您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關什么是C++的堆棧指引,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。
我們經常會討論這樣的問題:什么時候數據存儲在堆棧(Stack)中,什么時候數據存儲在堆(Heap)中。我們知道,局部變量是存儲在堆棧中的;debug時,查看堆棧可以知道函數的調用順序;函數調用時傳遞參數,事實上是把參數壓入堆棧,聽起來,堆棧象一個大雜燴。那么,堆棧(Stack)到底是如何工作的呢?本文將詳解C/C++堆棧的工作機制。閱讀時請注意以下幾點:
1)本文討論的編譯環境是VisualC/C++,由于高級語言的堆棧工作機制大致相同,因此對其他編譯環境或高級語言如C#也有意義。
2)本文討論的堆棧,是指程序為每個線程分配的默認堆棧,用以支持程序的運行,而不是指程序員為了實現算法而自己定義的堆棧。
3)本文討論的平臺為intelx86。
4)本文的主要部分將盡量避免涉及到匯編的知識,在本文最后可選章節,給出前面章節的反編譯代碼和注釋。
5)結構化異常處理也是通過堆棧來實現的(當你使用try…catch語句時,使用的就是c++對windows結構化異常處理的擴展),但是關于結構化異常處理的主題太復雜了,本文將不會涉及到。
1)程序的堆棧是由處理器直接支持的。在intelx86的系統中,堆棧在內存中是從高地址向低地址擴展(這和自定義的堆棧從低地址向高地址擴展不同),因此,棧頂地址是不斷減小的,越后入棧的數據,所處的地址也就越低。
2)在32位系統中,堆棧每個數據單元的大小為4字節。小于等于4字節的數據,比如字節、字、雙字和布爾型,在堆棧中都是占4個字節的;大于4字節的數據在堆棧中占4字節整數倍的空間。
3)和堆棧的操作相關的兩個寄存器是EBP寄存器和ESP寄存器的,本文中,你只需要把EBP和ESP理解成2個指針就可以了。ESP寄存器總是指向堆棧的棧頂,執行PUSH命令向堆棧壓入數據時,ESP減4,然后把數據拷貝到ESP指向的地址;執行POP命令時,首先把ESP指向的數據拷貝到內存地址/寄存器中,然后ESP加4。EBP寄存器是用于訪問堆棧中的數據的,它指向堆棧中間的某個位置(具體位置后文會具體講解),函數的參數地址比EBP的值高,而函數的局部變量地址比EBP的值低,因此參數或局部變量總是通過EBP加減一定的偏移地址來訪問的,比如,要訪問函數的第一個參數為EBP+8。
4)堆棧中到底存儲了什么數據?包括了:函數的參數,函數的局部變量,寄存器的值(用以恢復寄存器),函數的返回地址以及用于結構化異常處理的數據(當函數中有try…catch語句時才有,本文不討論)。這些數據是按照一定的順序組織在一起的,我們稱之為一個堆棧幀(StackFrame)。一個堆棧幀對應一次函數的調用。在函數開始時,對應的堆棧幀已經完整地建立了(所有的局部變量在函數幀建立時就已經分配好空間了,而不是隨著函數的執行而不斷創建和銷毀的);在函數退出時,整個函數幀將被銷毀。
5)在文中,我們把函數的調用者稱為caller(調用者),被調用的函數稱為callee(被調用者)。之所以引入這個概念,是因為一個函數幀的建立和清理,有些工作是由Caller完成的,有些則是由Callee完成的。
看完上述內容,你們對什么是C++的堆棧指引有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。