本文中,我们讨论如何在6个简单步骤下使用gdb调试器调试C程序。
为了调试目的编写一个带有错误的C程序示例。
为了学习C编程调试,让我们创建下面C程序,它计算并且打印一个数的阶乘。然而该C程序包括一些错误,它是为了我们调试目的而为。
$ vim factorial.c
# include <stdio.h>
int main()
{
inti, num, j;
printf("Enter the number: ");
scanf("%d", &num );
for(i=1; i<num; i++)
j=j*i;
printf("Thefactorial of %d is %d\n",num,j);
}
$ cc factorial.c
$ ./a.out
Enter the number: 3
The factorial of 3 is 12548672
让我们开始调试它,学习gdb中许多最有用的命令。
步骤1:使用编译选项-g编译C程序
使用-g选项编译你的C程序,这允许编译器收集调试信息。
$ cc -g factorial.c
注意:上面的命令创建一个a.out文件,它用于下面显示的调试。
步骤2:运行gdb
运行C调试器(gdb),如下所示:
$ gdb a.out
步骤3:在C程序中设置断点
语法:break line_number
其它的格式:
break [file_name]:line_number
break [file_name]:func_name
在C程序中你假设错误的地方放置断点。当执行程序时,调试器将在断点处停止,并且给你调试的提示。
因此在开始运行程序之前,让我们在程序中来设置下面的断点。
(gdb) break 10
Breakpoint 1 at 0x40050b: file factorial.c,line 10.
步骤4:在gdb调试器中执行C程序
run [args]
你也可以在dbg调试器中使用run命令启动程序。你也可以使用run args把命令行参数给程序。我们这里使用的例子程序不需要任何的命令行参数,让我们输入run让程序执行。
(gdb) run
Starting program: /root/valgrind/a.out
当你执行C程序,它会执行到第一个断点,并且给你调试的提示。
Breakpoint 1, main () at factorial.c:10
10 j=j*i;
你也可以使用下面章节说明的各种gdb命令来调试C程序。
步骤5:打印gdb调试器中的变量值
语法: print {variable}
Examples:
print i
print j
print num
(gdb) p i
$1 = 1
(gdb) p j
$2 = 3042592
(gdb) p num
$3 = 3
(gdb)
正如上面所示,在factorial.c中,我们没有初始化变量j,因此它给一个垃圾值作为阶乘的值。
通过初始化化j为1来修复这个问题,编译C程序并且再次执行它。
甚至在修复之后,在factorial.c程序中看上去也有一些问题,它仍然给错误的阶乘值。
因此,在第10行放置断点,并且继续下一节的说明。
步骤6:继续,单步执行-gdb命令
当程序停止在断点处时,这里有三种你可以选择的gdb操作。它们是继续执行到下一个断点,单步执行进入函数,或者单步执行到下一个程序行。
# c 或者 continue:调试器将继续执行直到下一个断点。
# n 或者 next:调试器将执行下一行作为单个指令;
# s 或者step:与next一样,但是不把函数作为单个指令,替代进入到函数中一行行的执行。
通过继续或者单步执行,你能发现问题是因为我们没有在for循环中使用<=条件检查。因此改变<为<=将解决这个问题。
Gdb命令快捷方式
使用下面最常用的gdb操作的快捷方式:
# l – list
# p – print
# c – continue
# s – step
# n – next
# ENTER: 输入回车键将再次执行前一个执行的命令。
万能的Gb命令
# l 命令:使用gdb命令l或list打印调试模式下的源代码,使用<l 行号>来查看指定行号或<l函数>查看指定的函数。
# bt:backtrack – 打印所有堆栈帧的信息,或者内部最多COUNT帧。
# help — 查看特别gdb主题的帮助— help 主题命
# quit – 退出gdb调试器。