1. 程式人生 > >linux應用程式設計筆記(1)gdb除錯方法及如何找出dbg.c程式中的錯誤

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,就可以了,下面

    其他的錯誤我沒有發現,就總結到這裡吧,如有不正確的地方,還請指出,大家共同進步。