<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>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                [TOC] # 函數進棧 前面我們只是講解了一個函數的活動記錄是什么樣子的,相信大家對函數的詳細調用過程的認識還不是太清晰,這節我們就以 VS2010 Debug 模式為例來深入分析一下。 請看下面的代碼: ~~~ void func(int a, int b){ int p =12, q = 345; } int main(){ func(90, 26); return 0; } ~~~ 函數使用默認的調用慣例 cdecl,即參數從右到左入棧,由調用方負責將參數出棧。函數的進棧出棧過程如下圖所示: ![](https://box.kancloud.cn/aeb7cf18e5014a93c191b5ef2ea7aee6_717x423.png) ![](https://box.kancloud.cn/35b5310fb7029610e6255bfca53a0674_712x701.png) ![](https://box.kancloud.cn/67056bc1395509617a2f795be0cddc6f_714x721.png) 步驟①到⑥是函數進棧過程: 1) main() 是主函數,也需要進棧,如步驟①所示。 2) 在步驟②中,執行語句`func(90, 26);`,先將實參 90、26 壓入棧中,再將返回地址壓入棧中,這些工作都由 main() 函數(調用方)完成。這個時候 ebp 的值并沒有變,僅僅是改變 esp 的指向。 3) 到了步驟③,就開始執行 func() 的函數體了。首先將原來 ebp 寄存器的值壓入棧中(也即圖中的 old ebp),并將 esp 的值賦給 ebp,這樣 ebp 就從 main() 函數的棧底指向了 func() 函數的棧底,完成了函數棧的切換。由于此時 esp 和ebp 的值相等,所以它們也就指向了同一個位置。 4) 為局部變量、返回值等預留足夠的內存,如步驟④所示。由于棧內存在函數調用之前就已經分配好了,所以這里并不是真的分配內存,而是將 esp 的值減去一個整數,例如 esp - 0XC0,就是預留 0XC0 字節的內存。 5) 將 ebp、esi、edi 寄存器的值依次壓入棧中。 6) 將局部變量的值放入預留好的內存中。注意,第一個變量和 old ebp 之間有4個字節的空白,變量之間也有若干字節的空白。 為什么要留出這么多的空白,豈不是浪費內存嗎?這是因為我們使用Debug模式生成程序,留出多余的內存,方便加入調試信息;以Release模式生成程序時,內存將會變得更加緊湊,空白也被消除。 至此,func() 函數的活動記錄就構造完成了。可以發現,在函數的實際調用過程中,形參是不存在的,不會占用內存空間,內存中只有實參,而且是在執行函數體代碼之前、由調用方壓入棧中的。 **未初始化的局部變量的值為什么是垃圾值** 為局部變量分配內存時,僅僅是將 esp 的值減去一個整數,預留出足夠的空白內存,不同的編譯器在不同的模式下會對這片空白內存進行不同的處理,可能會初始化為一個固定的值,也可能不進行初始化。 例如在VS2010 Debug模式下,會將預留出來的內存初始化為 0XCCCCCCCC,如果不對局部變量賦值,它們的內存就不會改變,輸出時的結果就是?0XCCCCCCCC,請看下面的代碼: ~~~ #include <stdio.h> #include <stdlib.h> int main(){ int m, n; printf("%#X, %#X\n", m, n); system("pause"); return 0; } ~~~ 運行結果: `0XCCCCCCCC, 0XCCCCCCCC ` 雖然編譯器對空白內存進行了初始化,但這個值對我們來說一般沒有意義,所以我們可以認為它是垃圾值、是隨機的 # 函數出棧 步驟⑦到⑨是函數 func() 出棧過程: 7) 函數 func() 執行完成后開始出棧,首先將 edi、esi、ebx 寄存器的值出棧。 8) 將局部變量、返回值等數據出棧時,直接將 ebp 的值賦給 esp,這樣 ebp 和 esp 就指向了同一個位置。 9) 接下來將 old ebp 出棧,并賦值給現在的 ebp,此時 ebp 就指向了 func() 調用之前的位置,即 main() 活動記錄的 old ebp 位置,如步驟⑨所示。 這一步很關鍵,保證了還原到函數調用之前的情況,這也是每次調用函數時都必須將 old ebp 壓入棧中的原因。 最后根據返回地址找到下一條指令的位置,并將返回地址和實參都出棧,此時 esp 就指向了 main() 活動記錄的棧頂, 這意味著 func() 完全出棧了,棧被還原到了 func() 被調用之前的情況。 **遺留的錯誤認知** 經過上面的分析可以發現,函數出棧只是在增加 esp 寄存器的值,使它指向上一個數據,并沒有銷毀之前的數據。前面我們講局部變量在函數運行結束后立即被銷毀其實是錯誤的,這只是為了讓大家更容易理解,對局部變量的作用范圍有一個清晰的認識。 棧上的數據只有在后續函數繼續入棧時才能被覆蓋掉,這就意味著,只要時機合適,在函數外部依然能夠取得局部變量的值。請看下面的代碼: ~~~ #include <stdio.h> int *p; void func(int m, int n){ int a = 18, b = 100; p = &a; } int main(){ int n; func(10, 20); n = *p; printf("n = %d\n", n); return 0; } ~~~ 運行結果: `n = 18 ` 在 func() 中,將局部變量 a 的地址賦給 p,在 main() 函數中調用 func(),函數剛剛調用結束,還沒有其他函數入棧,局部變量 a 所在的內存沒有被覆蓋掉,所以通過語句`n = *p;`能夠取得它的值。
                  <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>

                              哎呀哎呀视频在线观看