本文中主要借鉴两篇文章,进行了整合。若要查看原文内容,请直接跳转到最后页,有原文链接。
1. 什么是调试?
所谓调试(Debug),就是让代码一步一步慢慢执行,跟踪程序的运行过程。比如,可以让程序停在某个地方,查看当前所有变量的值,或者内存中的数据;也可以让程序一次只执行一条或者几条语句,看看程序到底执行了哪些代码。
在调试的过程中,我们可以监控程序的每一个细节,包括变量的值、函数的调用过程、内存中数据、线程的调度等,从而发现隐藏的错误或者低效的代码。
编译器可以发现程序的语法错误,调试可以发现程序的逻辑错误。所谓逻辑错误,是指代码思路或者设计上的缺陷。
对于初学者来说,学习调试也可以增加编程的功力,它能让我们更加了解自己自己的程序,比如变量是什么时候赋值的、内存是什么时候分配的,从而弥补学习的纰漏。
调试是每个程序员必须掌握的技能,没有选择的余地!
2. 调试器分类
调试需要借助专业的辅助软件——调试器(Debugger)。现在主流C/C++调试器有下面几种:
1) Remote Debugger
Remote Debugger 是 VC/VS 自带的调试器,与整个IDE无缝衔接,使用非常方便,初学者建议使用该调试器,本教程也以 VS2010 为例讲解调试技巧。
2) WinDbg
大名鼎鼎的 Windows 下的调试器,它的功能甚至超越了 Remote Debugger,它还有一个命令行版本(cdb.exe),但是这个命令行版本的调试器指令比较复杂,不建议初学者使用。
3) LLDB
XCode 自带的调试器,Mac OS X 下开发必备调试器。
4) GDB
Linux 下使用最多的一款调试器,也有 Windows 的移植版。
3. 关于 GDB
GDB 是 Linux 下的 C/C++ 程序调试工具,它开源免费,功能强大,但是命令众多,所以需要一段时间的学习。
正如从事 Windows C/C++ 开发的一定要熟悉 Visual Studio、从事 Java 开发的要熟悉 Eclipse 或 IntelliJ IDEA、从事 Android 开发的要熟悉 Android Studio、从事 iOS 开发的要熟悉 XCode 一样,从事 Linux C/C++ 开发要熟悉 GDB。
虽然 Linux 系统下读者编写 C/C++ 代码的 IDE 可以自由选择,但是调试生成的 C/C++ 程序一定是直接或者间接使用 GDB。可以毫不夸张地说,我所做那些 C/C++ 项目的开发和调试包括故障排查都是利用 GDB 完成的,调试是开发流程中一个非常重要的环节,因此对于从事 Linux C/C++ 的开发人员熟练使用 GDB 调试是一项基本要求。
“工欲善其事、必先利其器”,作为一名合格的软件开发者,至少得熟悉一种软件开发工具和调试器, 而对于 Linux C/C++ 后台开发,舍 GDB 其谁。
4. GDB调试
*启动程序准备调试
GDB yourpram
或者先输入GDB
,然后输入 file yourpram
然后使用 run
或者 r
命令开始程序的执行,也可以使用 run parameter将参数传递给该程序
5. 参数列表
//e.c
#include <stdio.h>
void debug(char *str)
{
printf("debug info :%s\n",str );
}
main(int argc,char *argv[]){
int i,j;
j=0;
for(i=0;i<10;i++){
j+=5;
printf("now a=%d\n", j);
}
}
gcc -g -o e e.c
调试 gdb e
或者输入 gdb
然后 file e
*list
命令用法*
list
命令显示多行源代码,从上次的位置开始显示,默认情况下,一次显示10
行,第一次使用时,从代码起始位置显示
gdb) list
1 #include <stdio.h>
2 void debug(char *str)
3 {
4 printf("debug info :%s\n",str );
5 }
6 main(int argc,char *argv[]){
7 int i,j;
8 j=0;
9 for(i=0;i<10;i++){
10 j+=5;
(gdb)
list n显示已第n行未中心的10行代码
(gdb) list 8
3 {
4 printf("debug info :%s\n",str );
5 }
6 main(int argc,char *argv[]){
7 int i,j;
8 j=0;
9 for(i=0;i<10;i++){
10 j+=5;
11 printf("now a=%d\n", j);
12 }
(gdb)
list functionname
显示以functionname
的函数为中心的10
行代码
(gdb) list main
1 #include <stdio.h>
2 void debug(char *str)
3 {
4 printf("debug info :%s\n",str );
5 }
6 main(int argc,char *argv[]){
7 int i,j;
8 j=0;
9 for(i=0;i<10;i++){
10 j+=5;
(gdb)
list -
显示刚才打印过的源代码之前的代码
(gdb) list 10
5 }
6 main(int argc,char *argv[]){
7 int i,j;
8 j=0;
9 for(i=0;i<10;i++){
10 j+=5;
11 printf("now a=%d\n", j);
12 }
13 }(gdb) list -
1 #include <stdio.h>
2 void debug(char *str)
3 {
4 printf("debug info :%s\n",str );
(gdb)
断点命令break
break location
:在location
位置设置断点,该位置可以为某一行,某函数名或者其它结构的地址
GDB
会在执行该位置的代码之前停下来
gdb) list
1 #include <stdio.h>
2 void debug(char *str)
3 {
4 printf("debug info :%s\n",str );
5 }
6 main(int argc,char *argv[]){
7 int i,j;
8 j=0;
9 for(i=0;i<10;i++){
10 j+=5;
(gdb)
11 printf("now a=%d\n", j);
12 }
13 }(gdb) break 10
Breakpoint 1 at 0x40050a: file e.c, line 10.
(gdb) r
Starting program: /mnt/hgfs/www/c/gcc/e
Breakpoint 1, main (argc=1, argv=0x7fffffffe548) at e.c:10
10 j+=5;
(gdb) c
Continuing.
now a=5
Breakpoint 1, main (argc=1, argv=0x7fffffffe548) at e.c:10
10 j+=5;
(gdb) c
Continuing.
now a=<