<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                [TOC] # 棧的概念 在計算機中,棧可以理解為一個特殊的容器,用戶可以將數據依次放入棧中,然后再將數據按照相反的順序從棧中取出。也就是說,先放入的數據最后才能取出,而最后放入的數據必須先取出。這稱為先進后出(First In Last Out)原則。 放入數據常稱為入棧或壓棧(Push),取出數據常稱為出棧或彈出(Pop)。如下圖所示 ![](https://box.kancloud.cn/d594e1a27a2023660dcce0e6c6ed6d47_672x273.png) 可以發現,棧底始終不動,出棧入棧只是在移動棧頂,當棧中沒有數據時,棧頂和棧底重合。 從本質上來講,棧是一段連續的內存,需要同時記錄棧底和棧頂,才能對當前的棧進行定位。在現代計算機中,通常使用`ebp`寄存器指向棧底,而使用`esp`寄存器指向棧頂。隨著數據的進棧出棧,esp 的值會不斷變化,進棧時 esp 的值減小,出棧時 esp 的值增大。 > ebp 和 esp 都是CPU中的寄存器:ebp 是 Extend Base Pointer 的縮寫,通常用來指向棧底;esp 是 Extend Stack Pointer 的縮寫,通常用來指向棧頂。 如下圖所示是一個棧的實例: ![](https://box.kancloud.cn/82c5bcb4fe1d9d818225195c8f52ac97_255x222.png) # 棧的大小以及棧溢出 對每個程序來說,棧能使用的內存是有限的,一般是 1M~8M,這在編譯時就已經決定了,程序運行期間不能再改變。如果程序使用的棧內存超出最大值,就會發生棧溢出(Stack Overflow)錯誤。 > 一個程序可以包含多個線程,每個線程都有自己的棧,嚴格來說,棧的最大值是針對線程來說的,而不是針對程序。 棧內存的大小和編譯器有關,編譯器會為棧內存指定一個最大值,在 VC/VS 下,默認是 1M,在 C-Free 下,默認是 2M,在 Linux GCC 下,默認是 8M。 當然,我們也可以通過參數來修改棧內存的大小。以 VS2010 為例,在工程名處右擊,會彈出一個菜單,選擇“屬性”,會出現一個對話框,如下圖所示: ![](https://box.kancloud.cn/53d86741e1cada5a5efe34c09a2abf18_505x298.png) 該圖中,我們將棧內存設置為 4M。提示:棧也經常被稱為堆棧,而堆依然稱為堆,所以堆棧這個概念并不包含堆,大家要注意區分 # 棧幀/活動記錄 當發生函數調用時,會將函數運行需要的信息全部壓入棧中,這常常被稱為棧幀(Stack Frame)或活動記錄(Activate Record)。活動記錄一般包括以下幾個方面的內容: 1. 函數的返回地址,也就是函數執行完成后從哪里開始繼續執行后面的代碼。例如: ~~~ int a, b, c; func(1, 2); c = a + b; ~~~ 站在C語言的角度看,func() 函數執行完成后,會繼續執行`c=a+b;`語句,那么返回地址就是該語句在內存中的位置。 > 注意:C語言代碼最終會被編譯為機器指令,確切地說,返回地址應該是下一條指令的地址,這里之所以說是下一條C語言語句的地址,僅僅是為了更加直觀地說明問題。 2. 參數和局部變量。有些編譯器,或者編譯器在開啟優化選項的情況下,會通過寄存器來傳遞參數,而不是將參數壓入棧中,我們暫時不考慮這種情況。 3. 編譯器自動生成的臨時數據。例如,當函數返回值的長度較大(比如占用40個字節)時,會先將返回值壓入棧中,然后再交給函數調用者。 > 當返回值的長度較小(char、int、long 等)時,不會被壓入棧中,而是先將返回值放入寄存器,再傳遞給函數調用者。 4. 一些需要保存的寄存器,例如 ebp、ebx、esi、edi 等。之所以要保存寄存器的值,是為了在函數退出時能夠恢復到函數調用之前的場景,繼續執行上層函數。 下圖是一個函數調用的實例: ![](https://box.kancloud.cn/3f000b53946d8e681553d1a5c5c5fe23_308x364.png) 上圖是在Windows下使用VS2010 Debug模式編譯時一個函數所使用的棧內存,可以發現,理論上 ebp 寄存器應該指向棧底,但在實際應用中,它卻指向了old ebp。 > 在寄存器名字前面添加“old”,表示函數調用之前該寄存器的值。 當發生函數調用時: * 實參、返回地址、ebp 寄存器首先入棧; * 然后再分配一塊內存供局部變量、返回值等使用,這塊內存一般比較大,足以容納所有數據,并且會有冗余; * 最后將其他寄存器的值壓入棧中。 需要注意的是,不同編譯器在不同編譯模式下所產生的函數棧并不完全相同,例如在VS2010下選擇Release模式,編譯器會進行大量優化,函數棧的樣貌蕩然無存,不具有教學意義,所以本教程以VS2010 Debug模式為例進行分析 # 關于數據的定位 由于 esp 的值會隨著數據的入棧而不斷變化,要想根據 esp 找到參數、局部變量等數據是比較困難的,所以在實現上是根據 ebp 來定位棧內數據的。ebp 的值是固定的,數據相對 ebp 的偏移也是固定的,ebp 的值加上偏移量就是數據的地址。 例如一個函數的定義如下: ~~~ void func(int a, int b){ float f = 28.5; int n = 100; //TODO: } ~~~ 調用形式為: ~~~ func(15, 92); ~~~ 那么函數的活動記錄如下圖所示: ![](https://box.kancloud.cn/b99a566ac3843115fcb5ac1dc0a4b890_316x453.png) 這里我們假設兩個局部變量挨著,并且第一個變量和 old ebp 也挨著(實際上它們之間有4個字節的空白),如此,第一個參數的地址是 ebp+12,第二個參數的地址是 ebp+8,第一個局部變量的地址是 ebp-4,第二個局部變量的地址是 ebp-8
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看