关于栈的理解(读书笔记)
生活随笔
收集整理的這篇文章主要介紹了
关于栈的理解(读书笔记)
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
關(guān)于棧的理解(讀書筆記)
標(biāo)簽: 棧內(nèi)存布局可執(zhí)行程序 2013-03-16 02:16 2957人閱讀 評(píng)論(1) 收藏 舉報(bào) 分類: 【C語(yǔ)言學(xué)習(xí)】(56)版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。
目錄(?)[+]
? ? 關(guān)于對(duì)棧的理解,相信很多人和我一樣都是很模糊的。在昨天閱讀數(shù)據(jù)的時(shí)候,看到對(duì)這方面的介紹,便寫個(gè)這個(gè)博客來(lái)和大家分享下。希望對(duì)大家有所幫助。
? ? ?棧,是硬件,主要作用表現(xiàn)為一種數(shù)據(jù)結(jié)構(gòu),是只能在一端插入和刪除數(shù)據(jù)的特殊線性表。允許進(jìn)行插入和刪除操作的一端稱為棧頂,另一端為棧底。棧按照后進(jìn)先出的原則存儲(chǔ)數(shù)據(jù),最先進(jìn)入的數(shù)據(jù)被壓入棧底,最后進(jìn)入的數(shù)據(jù)在棧頂,需要讀數(shù)據(jù)時(shí)從棧頂開(kāi)始彈出數(shù)據(jù)。棧底固定,而棧頂浮動(dòng)。棧中元素個(gè)數(shù)為零時(shí)稱為空棧。插入一般稱為進(jìn)棧(p u s h ),刪除則稱為出棧(p o p )。 ?棧也被稱為先進(jìn)后出表,在函數(shù)調(diào)用的時(shí)候用于存儲(chǔ)斷點(diǎn),在遞歸時(shí)也要用到棧。
? ? ?在計(jì)算機(jī)系統(tǒng)中,棧則是一個(gè)具有以上屬性的動(dòng)態(tài)內(nèi)存區(qū)域。程序可以將數(shù)據(jù)壓入棧中,也可以將數(shù)據(jù)從棧頂彈出。在i 3 8 6 機(jī)器中,棧頂由稱為e s p 的寄存器進(jìn)行定位。壓棧的操作使棧頂?shù)牡刂窚p小,彈出的操作使棧頂?shù)牡刂吩龃蟆?棧在程序的運(yùn)行中有著舉足輕重的作用。最重要的是,棧保存了一個(gè)函數(shù)調(diào)用時(shí)所需要
的維護(hù)信息,這常常被稱為堆棧幀。棧一般包含以下兩方面的信息:?
1 )函數(shù)的返回地址和參數(shù)。
2 )臨時(shí)變量:包括函數(shù)的非靜態(tài)局部變量及編譯器自動(dòng)生成的其他臨時(shí)變量。?
? ? ? ?堆,是一種動(dòng)態(tài)存儲(chǔ)結(jié)構(gòu),實(shí)際上就是數(shù)據(jù)段中的自由存儲(chǔ)區(qū),它是C 語(yǔ)言中使用的一種名稱,常常用于存儲(chǔ)、分配動(dòng)態(tài)數(shù)據(jù)。堆中存入的數(shù)據(jù)地址向增加方向變動(dòng)。堆可以不斷進(jìn)行分配直到?jīng)]有堆空間為止,也可以隨時(shí)進(jìn)行釋放、再分配,不存在順序問(wèn)題。堆內(nèi)存的分配常通過(guò)m a l l o c ( ) 、c a l l o c ( ) 、r e a l l o c ( ) 三個(gè)函數(shù)來(lái)實(shí)現(xiàn)。而堆內(nèi)存的釋放則使用f r e e ( ) 函數(shù)。
? ? ?堆和棧在使用時(shí)“生長(zhǎng)”方向相反,棧向低地址方向“生長(zhǎng)”,而堆向高地址方向“生長(zhǎng)”。
? ? [csharp] view plaincopyprint?
1 )p u s h 操作先移動(dòng)棧頂指針,之后將信息入棧。
2 )e s p 為堆棧指針,棧頂由e s p 寄存器來(lái)定位。壓棧的操作使棧頂?shù)牡刂窚p小,彈出的操作使棧頂?shù)牡刂吩龃蟆?br /> 3 )e b p 是3 2 位的b p ,是基址指針。b p 為基指針寄存器,用它可直接存取堆棧中的數(shù)據(jù),它在調(diào)用函數(shù)時(shí)保存e s p ,以便函數(shù)結(jié)束時(shí)可以正確返回。
4 )默認(rèn)的函數(shù)內(nèi)部變量的壓棧操作為:從上到下、從左向右,采用4 字節(jié)對(duì)齊。數(shù)組壓棧方法略有不同,即從最后一個(gè)元素開(kāi)始,直到起始元素為止,即采用從右向左的方法壓棧。
?函數(shù)的開(kāi)頭都有如下兩句匯編指令:
push ? ? ? ?ebp
mov ? ? ? ? ebp,esp
為了使讀者易于理解,在此通過(guò)圖1 - 1 來(lái)分析說(shuō)明。根據(jù)圖上的標(biāo)注,函數(shù)開(kāi)頭部分的第一個(gè)p u s h 指令的操作步驟是,首先移動(dòng)棧頂指針e s p ,然后將e b p 內(nèi)容壓棧,注意此時(shí)壓棧的e b p 的值為上一個(gè)函數(shù)的e s p 的值, ?而e s p 恰好就是上一個(gè)函數(shù)的棧底,所以每個(gè)函數(shù)一開(kāi)始的p u s h 指令就是保存上一個(gè)函數(shù)的棧底。那么接下來(lái)的m o v 指令有什么作用呢?由于e s p 是當(dāng)前的棧頂指針,所以該指令的作用就是保存當(dāng)前棧頂指針的值。由此就可以分析出,e b p 存放的是此刻棧頂?shù)牡刂?#xff0c;就是說(shuō),e b p 是一個(gè)指針,指向棧頂,而棧頂存放的數(shù)據(jù)其實(shí)是上一個(gè)函數(shù)的e b p 的值,即上一個(gè)函數(shù)的棧底。
? ? 通過(guò)上面的分析可知,e b p 壓棧后,接著就是函數(shù)中臨時(shí)變量的壓棧操作,由此可知,我們只需要在p r i n t ( ) 函數(shù)中得到m a i n ( ) 函數(shù)的棧底,就可以取出數(shù)組中的每個(gè)元素了,看看下面的實(shí)現(xiàn)方法。
[csharp] view plaincopyprint? ? ? ?在沒(méi)有傳遞任何參數(shù)的情況下,成功地在p r i n t ( ) 函數(shù)中打印出了m a i n ( ) 函數(shù)中a r r 數(shù)組內(nèi)的每個(gè)元素。現(xiàn)在來(lái)看看上面代碼的實(shí)現(xiàn)方法,在p r i n t ( ) 函數(shù)中定義了一個(gè)_ e b p 無(wú)符號(hào)整型變量,通過(guò)V C + + ? 6 . 0 內(nèi)嵌匯編把e b p 的值保持到_ e b p 中,按照上面的分析,可以將在函數(shù)p r i n t ( ) 中通過(guò)這條內(nèi)嵌匯編語(yǔ)句得到的e b p 看成一個(gè)指針,指針?biāo)赶虻膯卧娣诺木褪莗 r i n t ( ) 函數(shù)的上一個(gè)函數(shù)的棧底,在此是m a i n ( ) 函數(shù)的棧底。知道了_ e b p 的作用后,我們來(lái)分析下代碼,通過(guò)( i n t * ) _ e b p 將_ e b p 轉(zhuǎn)換為一個(gè)整型指針,然后通過(guò)* ( i n t * ) _ e b p 即可得到m a i n ( ) 函數(shù)的棧底地址。由于棧的壓棧操作是從上到下、從右到左的,所以m a i n ( ) 函數(shù)中的變量a 先壓棧,然后是b 、c ,最后是a r r 數(shù)組,數(shù)組的壓棧順序是從右到左。通過(guò)“i n t ?* p = ( i n t ? * ) ( * ( i n t ? * ) _ e b p - 4 - 4 - 4 - 7 * 4 ) ; ”即可得到數(shù)組元素的首地址。接下來(lái),根據(jù)首地址就可以取出數(shù)組中的每個(gè)元素了。有的讀者可能會(huì)有一個(gè)疑惑,m a i n ( ) 函數(shù)中有一個(gè)字符型變量,是不是在求數(shù)組元素的首地址時(shí)應(yīng)該把其中的減4 改為減1 呢?因?yàn)樗徽加昧艘粋€(gè)字節(jié)!即將“i n t ? * p = ( i n t ? * ) ( * ( i n t ? * ) _ e b p - 4 - 4 - 4 - 7 * 4 ) ; ”修改為“i n t ? * p = ( i n t ? * ) ( * ( i n t ? * ) _ e b p - 4 - 4 - 1 -7 * 4 ) ”。我們暫且不說(shuō)其對(duì)與錯(cuò),先來(lái)看看修改后的運(yùn)行結(jié)果:3072 ? ?3328 ? ?3584 ? ?3840 ? ?4096 ? ?4352 ? ?-859021056 ? ? ?
? ? ?我們發(fā)現(xiàn)這樣的運(yùn)行結(jié)果是錯(cuò)誤的,為什么呢?細(xì)心的讀者可能發(fā)現(xiàn)了本章一開(kāi)始回顧的知識(shí)點(diǎn)中有一點(diǎn)是很重要的,那就是壓棧操作為4 字節(jié)對(duì)齊。所以這里必須減4 ,而不是減1?
-------------------------------------------------------------以上是書本原話介紹---------------------------------------
? ? 閱讀完上面的代碼應(yīng)該會(huì)對(duì)棧有一定的了解。下面簡(jiǎn)單介紹下可執(zhí)行程序在內(nèi)存中的布局!
? ? ?
? ? ?數(shù)據(jù)段包含經(jīng)過(guò)初始化的全局和靜態(tài)變量及他們的數(shù)值。BSS段的大小從可執(zhí)行程序中得到,然后又連接器得到這個(gè)大小的內(nèi)存塊,緊跟在數(shù)據(jù)段的后面。當(dāng)這個(gè)內(nèi)存區(qū)進(jìn)行程序的地址空間后全部清零。包括數(shù)據(jù)段和BSS段的整個(gè)區(qū)域統(tǒng)稱為數(shù)據(jù)區(qū)。值得說(shuō)明的是局部變量并未編譯到可執(zhí)行程序中,是在程序運(yùn)行時(shí)執(zhí)行的。
總結(jié)
以上是生活随笔為你收集整理的关于栈的理解(读书笔记)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: python求输入数字的平方、如果平方运
- 下一篇: 字母c语言定义为什么变量,C语言为什么要