Ubuntu12.04下gdb調試C語言簡單程序詳解

一 reverse

        第一個源程序是在上一篇gcc編譯的博客裏,是個出現的問題很easy的程序。源代碼:源代碼。因爲問題不大,源代碼也並不長,所以涉及到的指令都是常用的基礎指令。

        reverse顧名思義就是反轉字符串。但是運行之後是這樣的:

        問題表現的超明顯啦,不多說,放技能~

   

        1. 終端輸入:

cd ~/Dwonloads
gdb reverse
//也可以只輸入gdb,然後輸入 file reverse加載文件,即file +filename。

         ~/Downloads是存儲reverse的目錄,先進入這個目錄。然後gdb filename進入調試模式,如圖:

        2. 明顯什麼都看不到,所以要用 list 命令顯示出我們想看到的源代碼,默認list顯示從文件中間行   作爲顯示的中間行   上下拓展共10行,因爲我們主要調試的是reverse函數,所以直接顯示函數,終端輸入:

list reverse //list可以簡寫成l
        這樣就會顯示出reverse函數,即list function name 顯示某個函數的源代碼。但僅僅是10行,顯示了才一半,所以我們要修改一下list顯示的行數,終端輸入:
set listsize 15//修改list一次性顯示的代碼數
list reverse
//也可以list 1 15 輸出1-15行,即list line1 line2 

        即 set listsize number 設置list 一次性顯示的代碼的行數。可以把set 改成show 察看此時的list的顯示行數。如圖,效果剛剛好。


        3. 接下來是設置斷點,這一步要在運行之前至少設置一個,否則運行起來就無法控制了。因爲這個函數比較簡單,所以只要在第9行循環處設置斷點就好了。終端輸入:

break 9 //直接break後面接行數。
break reverse //在函數的中間點設置斷點,不一定是你想要的點!
//break 12 if i>1  如果i>1就在第12行停止,同下面的watch用法相同。即 break linenum if condition
        4. 終端輸入:
run//開始運行程序
// 也可以輸入縮寫 r
        提示輸入字符串:

        輸入ABCDEFG,回車進入運行,可以看到到了斷點這裏停下了,如下:

        其實在這裏斷點很不科學,應該在11行設置,但這裏要介紹一下watch,所以就先在9行這裏停一下。

        在終端輸入:

watch i
//或 watch i if i<0 

        watch +變量名,當i的值變化時會自動停止執行。 watch +變量名+if +條件語句 可以當條件觸發時斷開,由於循環是i>=0,所以每次當i變化時都會停。如果循環1000次,設置條件 watch i if i>997,可以讓我們在任意想停下的循環次數停止而不用手動一次次的循環。       

        在終端輸入:

info break
//info locals 顯示現在所在的函數內的變量值。
        可以輸出所有斷點的信息,如圖:

        watch監視的是一個變量,只要變量發生變化不管在第幾行都會停止。而break只有在運行到第9行纔會停。

        在終端輸入:

delete 1
//或 d 1 ,只寫delete的縮寫d也可以。
        刪除第一號斷點,刪除後在重新建立其他斷點或監視點也不會是1號,而是一直向後排。

        終端輸入:

continue
//c 縮寫,可以替換寫
/* --------------辨析--------------
*Step 是單步執行,遇見函數會跳入函數內,c是直到斷點纔會停止。
*Next 也是單步執行,但遇到函數也會一步執行完,不會進入函數。可以在後面加上整數來跳若干步。
*/
        繼續執行程序。此時i =1觸發監視點,於是停了下來。可以看到有顯示i的old和new值作爲對比,但在本程序中監視c要比i好,所以終端輸入新建i的監視點:

info break//如果很清楚要刪除第幾號斷點可以不察看。
delete 2
// 可以用 clear N 刪除第N行以上所有的斷點。
 watch c
c//繼續執行 
        可以看到因爲c=*str+i執行後c變化了,所以又停下了:

        注意,函數本來是反轉字符串,可以看到A和G已經成功調換,但現在c='H',證明錯誤已經出現了。終端輸入:

info locals
        可以察看當前函數內的變量值:

        此時i=1,按照正常執行程序c='B'纔對,而i=1只執行了 c=*str+i這一步,所以我們先着重看一下這一句,終端輸入:

print *str 
p *str+i//p是print的縮寫,可替換。
        print+變量名 即輸出變量對應的現在的值,如圖:

        這裏可以從兩個方面分析,第一個是值,我們寫c = *str+i 本意是讓指針地址指向下一個字符,但現在變成了str的ASCii值加i,所以這裏應該是*(str+i)。另一個方面是類型,我們知道*str是char*類型的,指向下一個字符也應該是字符類型,但上下對比可以發現*str+i 至少不是char*,終端輸入:

ptype *str+i  //顯示錶達式或變量運算後的值的類型。
//輸出  type = int 
ptype *(str+i)
//輸出  type = char
        所以至少有一個問題出現在這裏,那麼還有沒有錯誤?我們先把c的值手動改回來,終端輸入:

set var c='B'
continue
        set var 後面接變量名=新值可以手動改變量的值。然後繼續運行。

        可以看到第二次交換完成進行第三次交換時c的值再次變化,由於未更改源代碼,所以c的值依舊是錯的,但可以看到在New value下面的一行有str的結果,可以看到由於我們改變了c的值,所以str的倒數第二位是正確的 ‘B’ ,但正數第二位卻成了‘L’,所以還有錯誤。可以看到第12行有和第11行同樣的問題,用同樣的方法測試其屬性:

ptype *(str+i)
//type = char
ptype *str +len-i-1
//type = int
        所以這個語句也要改成*(str+i) = *(str+len-i-1)。第十三行由於c對str的末尾賦值並沒有出現越界等錯誤,所以是沒有錯誤的。到此這個程序就調試完成了。終端輸入:

finish
/*--------------------辨析-------------
*return 也可以結束一個函數,但是並不會執行接下來的步驟!後面可以加 可作爲函數返回值的值 作爲返回值。
*/
        就會運行直到跳出函數reverse。

        按c繼續運行完畢,執行完程序後終端輸入:

quit
//q 縮寫,某些特殊時候無法正常退出時,可以在後面加上!來強制退出。
        會結束gdb模式。迴歸普通終端模式。改掉源代碼中的錯誤,再次運行,發現結果是正確的。

       

二 gdb-tui模式

        普通模式終端下輸入:

gdb -tui
        會調用gdb的tui模式,即文本用戶界面(交互式窗口),

        按回車翻倒下一頁,或者q+回車進入gdb Shell模式。

        終端輸入:

file reverse
        成功加載文件後上部分的窗口會自動調用該源代碼文件。

       

       使用tui模式好處是可以很好的觀察源代碼,不用list頻繁控制,但需要注意幾點:

                1. 此時按上下鍵控制的是顯示源代碼的窗口,命令行的上下鍵是Ctrl+n/p。

                2. 在輸入命令時無法插入,如果某個地方輸入錯誤需要刪到該處進行修改。

                3. 如果不是一步式編譯(見gcc編譯詳解),而是在源代碼文件夾內有中間生成的彙編代碼,那麼上部分窗口是會默認顯示彙編文件的代碼而不是源代碼。


三 補充常用命令:

                1. 輸入回車可以重複上一個命令。

                2. 如果在一個函數中只是想退出循環體而不是函數體可以把語句執行到循環體首行(for語句位置),輸入 until(u)就可以執行完循環體了。

                3. jump N 可以跳到第N行,是不執行中間行,即不會更新堆棧,所以儘量不要在不同函數之間跳,跳後會直接繼續運行直到斷點纔會停止。

               4.對於數組型變量可以用 print *str@num來顯示前num個元素,但不要越界。
               5. whatis+變量名 和ptype+變量名一樣可以打印出變量的類型信息。

四 總結

        對於這個例子的調試過程,顯得有些勉強,而且也比較簡單,但基本調試用到的命令幾乎都提到了,有的地方加了拓展對比,對於複雜源代碼的調試,是需要時間和精力練習的,從簡單的源代碼問題的調試一點點適應gdb是一件不那麼讓人反感的事情。在論壇上有人問過gdb的優點,一開始我也不爽爲什麼要學這麼“底層”到D炸天的東西,看完後大概有一點點心甘情願的感覺,反正感覺好像很全能的趕腳,vim也一樣,債多不壓身,一樣一樣慢慢熟練 T_T 。gdb的優點

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章