分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!
大內高手—棧/堆
作者****:李先靜
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 的記憶體模型,或許不能讓你大幅度提高程式設計能力,但是作為乙個基本知識點應該熟悉。坐火車外出旅行時,即時你對沿途的地方一無所知,仍然可以到達目標地。但是你對整個路途都很比較清楚的話,每到乙個站都知道自己在 知道當地的風土人情,對...