linux应用编程笔记(1)gdb调试方法及如何找出dbg.c程序中的错误

摘要: 介绍了gdb调试器以及其使用流程,总结了常用的几个gdb调试命令,最后使用这些方法找出dgb.c文件中的错误。


一、gdb简介

    gdb是gnu发布的一款功能强大的程序调试工具,其主要功能有如下三个:

    1.启动被调试的程序。

   2.让被调试的程序在指定的位置停住。

   3.当程序停住时,可以检查程序状态,例如变量的值。

    我们在gcc编译成功以后,运行程序还会出现逻辑错误,这样的错误需要调试,那么使用gdb就可以。


二、gdb使用流程

    这里编写一个测试函数gdb-test.c来延时gdb的使用流程,函数如下:

#include 
 
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);
}

    这个函数就是在for循环里实现result的自加,然后打印出来这个值。

    在编写好函数之后,可以按照下面的流程使用gdb:

    1.编译时加上-g选项

    # gcc –g gdb-test.c –o gdb-test

    2.启动gdb

    # gdb gdb-test

    这时候gdb就会启动,启动后的信息如下:

linux应用编程笔记(1)gdb调试方法及如何找出dbg.c程序中的错误_第1张图片

   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的内容如下:

#include  
 
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] ) ; 
       }
    }
} 

    这个函数的功能,输入五个学生的成绩,直到输入-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,没有任何输出信息。

    这就所谓的逻辑错误,程序在编译的时候没有语法错误,但是却得不到我们想要的值,刚才的操作步骤如下图:

    linux应用编程笔记(1)gdb调试方法及如何找出dbg.c程序中的错误_第2张图片

    那么我们开启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

    运行后按照刚才的操作,结果一切正常,输出信息如下:

   linux应用编程笔记(1)gdb调试方法及如何找出dbg.c程序中的错误_第3张图片

    确实打印出来了我们期望的值。但是刚才那个疑问还在,比如我们运行程序,我要输出的分数从0到100,这时候输出信息如下:

   linux应用编程笔记(1)gdb调试方法及如何找出dbg.c程序中的错误_第4张图片

    这个第六个成绩是哪里来的呢?我们只有五个成绩,而且也没有给6这个值,这是因为count++之后,变为了6,所以,去掉最后在find函数里面做一个小修改就可以了:

    for( i = 0 ; i < count-1 ; i++ )

    把这里的count改为count-1,就可以了,下面

    其他的错误我没有发现,就总结到这里吧,如有不正确的地方,还请指出,大家共同进步。

 

你可能感兴趣的:(Application)