摘要: 介绍了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就会启动,启动后的信息如下:
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,没有任何输出信息。
这就所谓的逻辑错误,程序在编译的时候没有语法错误,但是却得不到我们想要的值,刚才的操作步骤如下图:
那么我们开启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,就可以了,下面
其他的错误我没有发现,就总结到这里吧,如有不正确的地方,还请指出,大家共同进步。