如何判斷棧的增長方向?

2021-04-18 02:38:03 字數 1449 閱讀 8165

如何判斷棧的增長方向?

對於乙個用慣了i386系列機器的人來說,這似乎是乙個無聊的問題,因為棧就是從高位址向低位址增長。不過,顯然這不是這個問題的目的,既然把這個問題拿出來,問的就不只是i386系列的機器,跨硬體平台是這個問題的首先要考慮到的因素。

在乙個物質極大豐富的年代,除非無路可退,否則我們堅決不會使用彙編去解決問題,而對於這種有系統程式設計味道的問題,c是乙個不錯的選擇。那接下來的問題就是如何用c去解決這個問題。

c在**會用到棧呢?稍微了解一點c的人都會立刻給出答案,沒錯,函式。我們知道,區域性變數都存在於棧之中。似乎這個問題立刻就得到了解答,用乙個函式宣告兩個區域性變數,然後比較兩個變數的位址,這樣就可以得到答案。

等一下,怎麼比較兩個變數的位址呢?

先宣告的先入棧,所以,它的第乙個變數的位址如果是高的,那就是從上向下增長。「先宣告的先入棧」?這個結論從何而來?一般編譯器都會這麼處理。要是不一般呢?這種看似正確的方法實際上是依賴於編譯器的,所以,可移植性受到了挑戰。

那就函式加個引數,比較引數和區域性變數的位置,引數肯定先入棧。那為什麼不能區域性變數先入棧?第一反應是怎麼可能,但仔細想來又沒有什麼不可以。所以,這種方法也依賴於編譯器的實現。

那到底什麼才不依賴於編譯器呢?

不妨回想一下,函式如何呼叫。執行乙個函式時,這個函式的相關資訊都會出現棧之中,比如引數、返回位址和區域性變數。當它呼叫另乙個函式時,在它棧資訊保持不變的情況下,會把它呼叫那個函式的資訊放到棧中。

似乎發現了什麼,沒錯,兩個函式的相關資訊位置是固定的,肯定是先呼叫的函式其資訊先入棧,後呼叫的函式其資訊後入棧。那接下來,問題的答案就浮出了水面。

比如,設計兩個函式,乙個作為呼叫方,另乙個作為被呼叫方。被呼叫方以乙個位址(也就是指標)作為自己的入口引數,呼叫方傳入的位址是自己的乙個區域性變數的位址,然後,被呼叫方比較這個位址和自己的乙個區域性變數位址,由此確定棧的增長方向。

給出了乙個解決方案之後,我們再回過頭來看看為什麼之前的做法問題出在哪。為什麼乙個函式解決不了這個問題。前面這個大概解釋了函式呼叫的過程,我們提到,函式的相關資訊會一起送入棧,這些資訊就包括了引數、返回位址和區域性變數等等,在計算機的術語裡,有個說法叫棧幀,指的就是這些與一次函式呼叫相關的東西,而在乙個棧幀內的這些東西其相對順序是由編譯器決定的,所以,僅僅在乙個棧幀內做比較,都會有對編譯器的依賴。就這個問題而言,引數和區域性變數,甚至包括返回位址,都是相同的,因為它們在同乙個棧幀內,它們之間的比較是不能解決這個問題的,而它們就是乙個函式的所有相關資訊,所以,乙個函式很難解決這個問題。

好了,既然有了這個了解,顯然可以擴充套件一下前面的解決方案,可以兩個棧幀內任意的東西進行比較,比如,各自的入口引數,都可以確定棧的增長方向。

狂想一下,會不會有編譯器每次專門留下些什麼,等下乙個函式的棧幀入棧之後,在把這個留下的東西入棧呢?這倒是個破壞的好方法。如果哪位知道有這麼神奇的編譯器,不妨告訴我。我們可以把它的作者拉過來打一頓,想折磨死誰啊!

判斷棧的增長方向

dreamhead老大曾經討論過這個問題,尋找一種可移植的方式來判斷棧的增長方向,見 棧的增長方向 今天在讀ruby hacking guide第5章,介紹alloca函式的部分,提到ruby實現的c語言版本的alloca.c,讀了下 發現這裡倒是實現了乙個很漂亮的函式用於 實現判斷棧的增長方向,利...

系統棧的增長方向判斷

函式呼叫時引數入棧,因此可以定義兩個函式,分別輸出引數位址,以此來確定棧的生長方向。cpp view plain copy print?確定棧的生長方向 自定義函式fun1 和fun2 其中fun1 內部呼叫fun2 輸出引數位址 include void fun2 intb void fun1 i...

棧的增長方向

如何判斷棧的增長方向?對於乙個用慣了i386系列機器的人來說,這似乎是乙個無聊的問題,因為棧就是從高位址向低位址增長。不過,顯然這不是這個問題的目的,既然把這個問題拿出來,問的就不只是i386系列的機器,跨硬體平台是這個問題的首先要考慮到的因素。在乙個物質極大豐富的年代,除非無路可退,否則我們堅決不...