昨天遇到乙個很奇怪的問題,如下:
按照理論,最後*p的值應該是99,不知為什麼是15了,所以今天記錄用gdb除錯的過程,並熟悉gdb的使用。
(除錯過程參考:
開始:1.
2.(用list從第1行開始列出原始碼)
3.(一次只列10行,如果要從第11行開始繼續列源**可以輸入list)
4.(也可以什麼都不輸直接敲回車,gdb
提供了乙個很方便的功能,在提示符下直接敲回車表示重複上一條命令。)
5.(gdb
的很多常用命令有簡寫形式,例如list
命令可以寫成l
,要列乙個函式的源**也可以用函式名做引數:)
6.(退出gdb環境)
7.(現在將niuke.cpp改名,然後gdb就列不出原始碼了)
說明:gcc
的-g
選項並不是把源**嵌入到可執行檔案中的,在除錯時也需要原始檔。
8.(原始碼檔案恢復,重新開始)
gdb
停在main
函式中變數定義之後的第一條語句處等待我們發命令,gdb
列出的這條語句是即將執行的下一條語句。
9.(我們可以用next
命令(簡寫為n
)控制這些語句一條一條地執行)
說明:用n函式f()中的結果一下就列印出來了
10.(現在用start重新開始,用step命令(簡寫s)進入f()中去跟蹤執行)
現在進入了f()函式。
11.(在函式中有幾種檢視狀態的辦法,backtrace
命令(簡寫為bt
)可以檢視函式呼叫的棧幀)
可見當前f()是被main()呼叫的,傳入指標p傳給ret=0xbfffee94
12.(檢視當前f()函式內區域性變數的值i locals 或者info locals)
13.(如果想檢視main
函式當前區域性變數的值也可以做到,先用frame
命令(簡寫為f
)選擇1號棧幀然後再檢視區域性變數,i locals, info locals)
14.(繼續執行,然後用p+變數名檢視變數的值)
這裡......$5,$6,$7,$8......分別儲存了檢視的中間值:
未執行*ret = &a時:
ret: 0xbfffee94(為&p) *ret:0xbfffef54(p) **ret:-1073745577
執行*ret = &a後:
ret: 0xbfffee94 *ret:0xbfffee68 = &a:0xbfffee68(值為99) **ret:99(等於a)
15.(finish命令讓程式一直執行到當前函式結束)
返回值是ret=0xbfffee94(&p)
16.(現在繼續執行)
注意:a &p address : 0xbfffee94(&p未改變) a p address : 0xbfffee68(與&a相同)a *p value : 15(奇怪的地方,為什麼不是99)
17.(換一種思路:在執行 cout << "a &p address : " << &p << endl; 之前直接檢視*p)
這裡可以看到*p=99,是正確的,位址也與上面相同
18.(繼續除錯)
這裡發現*p=15,被改變了。
也就是說:在執行cout << "a &p address : " << &p << endl;後, *p的值被改變了,從99變為15了。
19.(連續輸出兩次*p)
這次發現第一次輸出結果正常,第二次輸出結果出錯,那為什麼呢?為什麼呢?????
20.(知道原因了)
說明:a是乙個區域性變數,&a在f()執行完後就被系統**了。f()中ret = &a 這一步,使得p=&a,所以最後p輸出不對。修改後:
這裡終於正確了。
ps:前面一種情況,棧被系統**,但是仍能輸出一次99,我猜可能是系統還沒來的及**。。。
pss:指標太容易出錯了。。
Linux下gdb除錯學習
以test.cpp為例 include include int main std cout下面是gcc g 常用編譯選項,我們的可執行檔案要能夠被gdb除錯,必須在編譯時加上除錯資訊,也即是加上 g選項 完整命令如下 g g test.cpp o test 執行gdb test 進入gdb除錯 種種...
gdb除錯學習
一般來說,gdb主要幫忙你完成下面四個方面的功能 1 啟動你的程式,可以按照你的自定義的要求隨心所欲的執行程式。2 可讓被除錯的程式在你所指定的調置的斷點處停住。斷點可以是條件表示式 3 當程式被停住時,可以檢查此時你的程式中所發生的事。4 動態的改變你程式的執行環境。除錯的程式如下 root lo...
gdb除錯學習
gdb是乙個由gnu開源組織發布的,unix linux作業系統下的,基於命令列,功能強大的程式除錯工具。可以用來除錯c,c 程式。在今天驗收實驗時發生特別尷尬的事情,由於在編譯.c檔案的時候沒有加 g選項,所以一直無法用gdb除錯程式,所以在總結gdb之前先來看看gcc在編譯時的引數。a.常規選項...