大內高手 棧 堆

2021-08-31 02:44:20 字數 1885 閱讀 2254

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!

大內高手—棧/堆

作者****:李先靜

l

棧作為一種基本資料結構,我並不感到驚訝,用來實現函式呼叫,這也司空見慣的作法。直到我試圖找到另外一種方式實現遞迴操作時,我才感嘆於它的巧妙。要實現遞迴操作,不用棧不是不可能,而是找不出比它更優雅的方式。

儘管大多數編譯器在優化時,會把常用的引數或者區域性變數放入暫存器中。但用棧來管理函式呼叫時的臨時變數(區域性變數和引數)是通用做法,前者只是輔助手段,且只在當前函式中使用,一旦呼叫下一層函式,這些值仍然要存入棧中才行。

通常情況下,棧向下(低位址)增長,每向棧中push

乙個元素,棧頂就向低位址擴充套件,每從棧中pop

平台上,棧頂暫存器為esp

,那麼esp

的值在是push

操作之前修改呢,還是在push

操作之後修改呢?push esp

這條指令會向棧中存入什麼資料呢?據說x86

系列cpu

中,除了286

外,都是先修改esp

,再壓棧的。由於286

沒有cpuid

指令,有的os

用這種方法檢查286

的型號。

乙個函式內的區域性變數以及其呼叫下一級函式的引數,所占用的記憶體空間作為乙個基本的單元,稱為乙個幀(frame)

。在gdb

裡,f

命令就是用來檢視指定幀的資訊的。在兩個frame

之間通過還存有其它資訊,比如上一層frame

的分界位址(ebp)等。

關於棧的基本知識,就先介紹這麼多,我們下面來看看一些關於棧的技巧及應用:

1.backtrace

的實現 callstack

偵錯程式的基本功能之一,利用此功能,你可以看到各級函式的呼叫關係。在gdb

中,這一功能被稱為backtrace

,輸入bt

命令就可以看到當前函式的callstack

。它的實現多少有些有趣,我們在這裡研究一下。

我們先看看棧的基本模型

引數n↓高位址

引數…           

函式引數入棧的順序與具體的呼叫方式有關

引數3           

引數2           

引數1           

eip           

ebp儲存呼叫者的ebp

,然後ebp

指向此時的棧頂。

臨時變數1

臨時變數2

臨時變數3

臨時變數…

臨時變數5

↓低位址

要實現callstack

我們需要知道以下資訊:

l呼叫函式時的指令位址(即當時的eip

)。 l

指令位址對應的源****位置。

關於第一點,從上表中,我們可以看出,棧中存有各級eip

的值,我們取出來就行了。用下面的**可以輕易實現:

#include

<

stdio

.h>

intbacktrace

(void

** buffer

, int

size

)return

size;}

#define n4

static

void

test2();

backtrace

(buffer, n

);給我老師的人工智慧教程打call!

大內高手 序

大內高手 序作者 李先靜 我一直認為作為乙個在linux 下工作的c 程式設計師,若對記憶體有深刻的認識,不但程式的效能會更高,執行更穩定,程式設計速度也會更快。反之亦有相反的效果,有時一些記憶體錯誤讓你摸不著頭腦,不但大大降低開發速度,開發出來的軟體穩定性也值得懷疑。為了提高組員的程式設計水平,去...

大內高手 記憶體模型

大內高手 記憶體模型 了解linux的記憶體模型,或許不能讓你大幅度提高程式設計能力,但是作為乙個基本知識點應該熟悉。坐火車外出旅行時,即時你對沿途的地方一無所知,仍然可以到達目標地。但是你對整個路途都很比較清楚的話,每到乙個站都知道自己在 知道當地的風土人情,對比一下所見所想,旅程可能更有趣一些。...

大內高手 記憶體模型

大內高手 記憶體模型 作者 李先靜 2007 7 9 了解 linux 的記憶體模型,或許不能讓你大幅度提高程式設計能力,但是作為乙個基本知識點應該熟悉。坐火車外出旅行時,即時你對沿途的地方一無所知,仍然可以到達目標地。但是你對整個路途都很比較清楚的話,每到乙個站都知道自己在 知道當地的風土人情,對...