代码监视
正如我们在前面所提到的,当程序并未按我们预期的那样运行时,重读我们的程序是一个好主意。出于本章的目的,我们假设代码已经进行重新检查,并且明显的错误已经进行了处理。
我们可以使用一些工具来帮助我们进行代码检查,编译器就是明显的一个。如果在我们的程序中存在任何语法错误,编译器可以通知我们。
我们在后面还会提到其他的工具,lint与Splint。与编译器类似,他们会分析代码并且报告不正确的代码。
监视
监视就是为了收集更多程序运行的行为信息而在程序添加的代码。正如在我们的例子中所做的,我们通常会添加printf调用来输出程序运行过程中不同阶段的变量值。我们通常可以添加多个printf调用,但是我们必须清楚的是程序必须经过修改并且在程序修改后要进行编译,当然,当bug被修复后我们需要移除这些代码。
在这里我们有两个监视工具可用。第一种方法使用C预处理器来选择性的包含监视代码,从而我们只需要重新编译程序来包含或是排除调试代码。我们可以使用如下的结构来简单做到:
#ifdef DEBUG
printf(“variable x has value = %d\n”, x);
#endif
我们可以使用编译器选项-DDEBUG编译程序来定义DEBUG符号并且包含这些额外的代码或是不带这个编译选项来排除这些代码。我们可以使用更为复杂的数字调试宏,如下所示:
#define BASIC_DEBUG 1
#define EXTRA_DEBUG 2
#define SUPER_DEBUG 4
#if (DEBUG & EXTRA_DEBUG)
printf...
#endif
在这种情况下,我们必须总是定义DEBUG宏,但是我们可以设置他来代表一个调试信息集合,或者一个详细级别。在这个例子中,编译器选项-DDEBUG=5将会允许BASIC_DEBUG与SUPER_DEBUG,但不是EXTRA_DEBUG。标记-DDEBUG=0将会禁止所有的调试信息。相对应的,包含下面的代码就排除了在不需要调试的情况下在命令行指定DEBUG的需要:
#ifndef DEBUG
#define DEBUG 0
#endif
C预处理器定义的一些宏有助于调试信息。这些宏会进行扩展给出有关当前编译的一些信息。
宏 描述
__LINE__ 表示当前行号的十进制常数
__FILE__ 表示当前文件名的字符串
__DATE__ 以"Mmm dd yyyy"格式表示的当前日期
__TIME__ 以"hh:mm:ss"格式表示的当前时间
注意,这些符号都是以两个下划线为前缀和后缀的。这是标准预处理器的通常做法,而我们应该小心避免选择会造成冲突的符号。在上面描述中的术语"当前"是指预处理器执行的时间,也就是编译器运行与文件处理的时间与日期。
试验--调试信息
下面是程序cinfo.c,这个程序会允许调试的情况下输出其编译信息。
#include <stdio.h>
int main()
{
#ifdef DEBUG
printf(“Compiled: “ __DATE__ “ at “ __TIME__ “\n”);
printf(“This is line %d of file %s\n”, __LINE__, __FILE__);
#endif
printf(“hello world\n”);
exit(0);
}
当我们在打开调试(使用-DDEBUG)的情况下编译这个程序,我们可以看到编译信息。
$ cc -o cinfo -DDEBUG cinfo.c
$ ./cinfo
Compiled: Mar 1 2003 at 18:17:32
This is line 7 of file cinfo.c
hello world
$
工作原理
当编译器编译时,其C预处理器部分会记录当前行号与文件。当遇到__LINE__与__FILE__时会将其替换为当前的变量值。日期与时间的用法与其相类似。因为__DATE__与__TIME__是字符串,我们可以使用printf格式化字符将他们合并,因为ANSI C将合并的字符串看作一个字符串。
不重新编译而调试
在我们继续之前,很值得指出一点:有一个方法可以使用printf函数帮助调试而不使用#ifdef DEBUG技术,而后者需要一个程序在可以使用之前必须进行重新编译。
这个方法是添加一个全局变量作为调试标记,允许在命令行使用-d选项,从而使用用户即使在程序发布之后也可以选择开头调试,并添加一个调试记录函数。现在我们就可以在我们的程序代码中添加如下的代码:
if (debug) {
sprintf(msg, ...)
write_debug(msg)
}
如果程序并不是实际使用我们可以将调试信息输出到stderr,或是使用syslog函数所提供的日志功能。
如果我们添加此类的跟踪代码为解决开发过程中的问题,只需要将他们留下那里就可以了。假如我们多加小心,这是相当安全的。当程序发布时我们就可以感受到这样做的好处;如果用户遇到问题,他们可以使用调试模式来运行,并且为我们诊断错误。与程序仅是输入内存错误信息不同,这样做可以报告程序此时实际做什么,而不仅是用户正是做什么。其中的区别是很明显的。
这个方法有一个明显的缺点;程序要比需要的大得多。在大多数情况下,这是比实际更为明显的一个问题。程序的规模将会大出20%到30%,但是在多数情况下这并不会对性能有什么实际的影响。差的情能来自由功能规模的巨大变化。
执行控制
让我们回到我们的例子程序。我们的程序有一个bug。我们可以修改程序添加一些额外的代码来输出程序运行时的变量值,或是我们可以使用一个调试器来控制程序的执行并且在处理执行时查看其状态。
在商业Unix系统,依据其提供者有大量的调试器可用。通常的调试有adb,sdb,与dbx。更为复杂的调试器允许我们在源代码级别详细的查看程序的状态。对于sdb,dbx是如此,而对于GNU调试器也是如此,后者可以用在Linux系统上。还存在gdb的前端,从而会使得gdb更为友好;xxgdb,tgdb,以及ddd就是这样的程序。一些IDE,例如我们在第9章所看到的,也提供了调试程序或是gdb的前端。Emacs编辑也具有一个实用程序允许我们在程序上运行gdb,设置断点,以及查看当前执行的源代码等。
要准备一个程序用于调试,我们需要使用一个或是多个特殊的编译选项来编译程序。这些选项会指示编译在程序中包含额外的调试信息。这些信息包括符号与行号信息,调试器可以使用这些信息向用户显示程序执行到了何处。
-g标记是编译一个程序用于调试时最常用到的选项。我们必须这个选项来编译每一个需要进行调试的源文件,同时也要用于链接器,从而可以使用标准C库的特殊版本来在库函数中提供调试支持。编译器程序会自动向链接器传递这些信息。调试也可以用于并不是为此目的而编译的库,但是具有更少的灵活性。
调试信息会使用可执行程序时间加倍变长。尽管可执行程序变大(而且需要更多的磁盘空间),程序运行所需要的内存数量是一样的。通常在我们发布程序之前移除这些调试信息是一个好主意,但是只有在我们调试之后才可以这样。
注:我们可以通过运行strip <file>来由一个可执行文件中移除调试信息,而不需要重新编译。
分享到:
相关推荐
点动长动控制电路的分析接线与调试二PPT课件.pptx
二合一串口网络调试助手, 集成一个串口和一个网口调试软件, 绿色,
这是二进制炸弹博客的文章所需内容,里面包括bomb.exe,可直接打开运行,并且带有GDB工具和objdump工具,还有它们的文档。 改成0积分下载
TCPCOM,网络与串口二合一调试助手,将网络调试助手与串口调试助手合二为一,绿色软件,简单高效
中介接单统计工具 文章接单 远程调试 二次开发 实时数据更新 中介接单统计工具 文章接单 远程调试 二次开发 实时数据更新 中介接单统计工具 文章接单 远程调试 二次开发 实时数据更新 中介接单统计工具 文章接单 ...
软件调试第二版卷一硬件基础.pdf格式
有人串口调试助手和网络调试助手合二为一,特别适合调试网络设备。 2. 支持中文和英文双语言,再也不用愁找不到合适的串口调试软件给国际客户用了。 3. 最小化时停留在右下角,不占用任务栏位置,需要时一键调入。 4...
中介接单统计工具 多人操作 实时更新数据 可远程调试 二次开发 中介接单统计工具 多人操作 实时更新数据 可远程调试 二次开发 中介接单统计工具 多人操作 实时更新数据 可远程调试 二次开发 中介接单统计工具 多人...
一款网络调试工具,工具提供二次开发接口。按照文档步骤进行即可。
网络设备调试实验二 熟练掌握路由器的密码恢复过程。熟练配置静态路由、RIP协议和IGRP协议。
很好用的串口 网口二合一调试工具
所以c#目前已成为AutoCAD二次开发的首选编程语言,但是当c#的开发者在享受c#开发便利的时候,又发现了一个严重的缺陷,那就是修改了代码想重新调试时不得不重启AutoCAD,因为.net的机制限制了c#编译的dll只能加载到...
智能变电站新技术及二次系统调试
串口,TCP通信的调试工具,可以多开,方便调试
HX108-2 AM收音机的组装与调试 二.主要内容: 1、学习收音机原理 2、组装、焊接收音机 3、书写课程设计报告 三.具体要求: 1、对照原理图讲述整机工作原理; 2、对照原理图看懂装配接线图; 3、了解图上符号,并与...
软件调试第二版卷一硬件基础.mobi格式
DrX调试寄存器使用 二例子,硬件断点编程
GDB中应该知道的几个调试方法 一、多线程调试二、调试宏三、源文件四、条件断点五、命令行参数六、gdb的变量七、x命令八、command命令
将串口调试助手与以太网调试助手整合在一起了。可以在同一界面上干两个活
本书是直面软件工程中的最困难任务——侦错,围绕软件世界中的最强大工具——调试器,全方位地展示了软件调试技术的无比威力和无穷魅力。 全书主要内容包括:CPU的调试支持;Windows操作系统中的调试设施;Visual C/...