linux應用程式設計筆記(1)gdb除錯方法及如何找出dbg.c程式中的錯誤
摘要: 介紹了gdb偵錯程式以及其使用流程,總結了常用的幾個gdb除錯命令,最後使用這些方法找出dgb.c檔案中的錯誤。
一、gdb簡介
gdb是gnu釋出的一款功能強大的程式除錯工具,其主要功能有如下三個:
1.啟動被除錯的程式。
2.讓被除錯的程式在指定的位置停住。
3.當程式停住時,可以檢查程式狀態,例如變數的值。
我們在gcc編譯成功以後,執行程式還會出現邏輯錯誤,這樣的錯誤需要除錯,那麼使用gdb就可以。
二、gdb使用流程
這裡編寫一個測試函式gdb-test.c來延時gdb的使用流程,函式如下:
<span style="font-size:24px;">#include <stdio.h> void myprint(int res) { printf("result= %d \n", res); } void main(void) { inti; longresult = 0; for(i=1;i<=100; i++) { result+= i; } myprint(result); }</span>
這個函式就是在for迴圈裡實現result的自加,然後打印出來這個值。
在編寫好函式之後,可以按照下面的流程使用gdb:
1.編譯時加上-g選項
# gcc –g gdb-test.c –o gdb-test
2.啟動gdb
# gdb gdb-test
這時候gdb就會啟動,啟動後的資訊如下:
3.在main函式時設定端點
第一個休息點,一般設定為main函式:
#break main
4.執行程式
#run
5.利用更多的命令對程式進行除錯。
下面對gdb的更多命令總結。
三、gdb命令
list(l)檢視程式
可以使用list檢視程式。
break(b) 函式名 在某函式入口處新增斷點
設定端點之後,程式執行到這裡就會停住,這裡可以指定函式名。
break(b) 行號 在指定行新增斷點
指定到哪一行停住
break(b) 檔名:行號 在指定檔案的指定行新增斷點
用於多檔案編譯,可以設定在哪個檔案中的哪一行設定斷點。
info break 檢視所有設定的斷點
檢視我們已經設定了哪些端點,按照次序會從1開始排序,哪些不需要的可以使用delete刪除。
delete 斷點編號 刪除斷點
next(n)
step(s) 單步執行程式(進入子函式)
continue(c) 繼續執行程式
從當前位置急需執行,知道下一個斷點停住。
print(p) 變數名 檢視指定變數值
set var=value 設定變數的值
quit(q) 退出gdb
以上命令都可以在上面編寫的測試函式裡進行測試,這裡就不粘貼出來了。
四、除錯dgb.c並找出其中的錯誤
dgb.c的內容如下:
<span style="font-size:18px;">#include <stdio.h>
int EnterScore ( int P_array[] ) ;
void find ( int P_array[] , int count ) ;
int main ( void )
{
intarray[5] , count ;
EnterScore( array ) ;
find( array , count ) ;
return0 ;
}
int EnterScore ( int P_array[] )
{
intcount = 0 ;
do
{
printf( "Enter students' score : \n" ) ;
scanf( "%d" , &(P_array[count]) ) ;
count++;
}while ( P_array[ count - 1 ] != -1 ) ;
returncount ;
}
void find ( int P_array[] , int count )
{
intx , y , i ;
printf( "Enter the students' score's scope : \n" ) ;
scanf( "%d,%d" , &x , &y ) ;
for( i = 0 ; i < count ; i++ )
{
if( P_array[i] >= x && P_array[i] <= y )
{
printf( "The score is %d.\n" , P_array[i] ) ;
}
}
} </span>
這個函式的功能,輸入五個學生的成績,直到輸入-1的時候,停止輸入,接著輸入一個分數的範圍,然後輸出在這個範圍內的學生的成績。
我們將其編譯,加上除錯選項:
#gcc –g dgb.c –o dgb
編譯通過,然後執行:
#./dgb
然後出現了Enter students' score :
我分別輸入了五個成績:11,22,33,44,55,然後輸入-1,開始要求Enter the students' score's scope :,然後我輸入20,30,沒有任何輸出資訊。
這就所謂的邏輯錯誤,程式在編譯的時候沒有語法錯誤,但是卻得不到我們想要的值,剛才的操作步驟如下圖:
那麼我們開啟gdb除錯,來看看問題到底出在哪裡:
#gdb dgb
#break main
#run
然後我們在兩個重要的函式之前都加上斷點:
#break EnterScore
#break find
在find之前,我們需要準備好兩個引數,一個是陣列,一個是count,我們的EnterScore做的就是這兩個事情,那麼我們讓程式執行到find之前:
#continue
#continue
這時候程式需要你輸入學生的成績,按照我剛才的輸入11,22,33,44,55,然後輸入結束輸入-1,之後執行到find之前停住了,我們列印一下當前的變數:
#printcount
發現這個值是-1!-1的話,肯定就錯了,傳到下面去的話,就沒有辦法進行查找了,再列印一下數組裡面的值:
#printP_arry[0]
#printP_arry[1]
#printP_arry[2]
#printP_arry[3]
#printP_arry[4]
前面五個分別輸出11,22,33,44,55,這裡說明get成績是對了,但是count是錯誤的。
看EnterScore,在它裡面count=0,然後每次輸入一個數,count都會自加1,但是最後return count的值之後,下面沒有哪一個語句有比如count= EnterScore,這種右值呼叫方式,我們可以切進去看看,在EnterScore裡面,還未退出函式之前,count的值是多少,這裡在return之前設定一個斷點:
#break 23
然後重新執行程式:
#run
#continue
這時候停在了EnterScore這裡我們列印一下count的值:
#printcount
輸出是0!
#continue
這時候我們輸入分數11,22,33,44,55然後輸入-1,之後就停在了return count這個地方,我們再列印一下:
#printcount
輸出6!為什麼是6呢?在這個函式裡顯然是對的,因為我們輸入了6次,最後一次輸入-1,做判斷while ( P_array[ count - 1 ] != -1 ) ;也是機會判斷P_array[ 5] != -1,不過這時候我有個疑問,因為我們在定義陣列的時候int array[5]只分配給了它5個單元,這裡已經到了P_array[ 5],也就是第六個單元了,會不會造成陣列越界,導致core dump呢?剛才執行的時候還沒有,不知道是我判斷錯了,還是編譯器比較“健壯”。
這裡先不管這個,先把count的事兒解決了,這裡count還是6怎麼到了find就變成了-1呢?我們繼續執行:
#continue
然後再列印count的值:
#printcount
又變成-1了,這個-1是哪裡來的呢?我也不知道具體哪裡來的,但是我可以肯定的是這個count和我們EnterScore裡面的count是不一樣的,所以這裡我們做出修改,把EnterScore的返回值count賦給find,具體修改如下:
intmain ( void )
{
intarray[5] , count_enter ;
count_enter=EnterScore( array ) ;
find( array , count_enter ) ;
return0 ;
}
我只把main函式裡面原來定義的count改為了count_enter,然後把EnterScore的返回值給他,這樣它就拿到了真正的count,然後再傳給find,這樣我們在進行編譯:
#gcc –g dgb.c –o dgb
#./dgb
執行後按照剛才的操作,結果一切正常,輸出資訊如下:
確實打印出來了我們期望的值。但是剛才那個疑問還在,比如我們執行程式,我要輸出的分數從0到100,這時候輸出資訊如下:
這個第六個成績是哪裡來的呢?我們只有五個成績,而且也沒有給6這個值,這是因為count++之後,變為了6,所以,去掉最後在find函式裡面做一個小修改就可以了:
for( i = 0 ; i < count-1 ; i++ )
把這裡的count改為count-1,就可以了,下面
其他的錯誤我沒有發現,就總結到這裡吧,如有不正確的地方,還請指出,大家共同進步。