更多调试策略
本节阅读量:在上一课中,我们开始探索如何手动调试问题。在课程末尾,我们指出了使用打印语句进行调试的一些缺点:
- 调试语句扰乱了代码
- 调试语句扰乱了输出内容
- 调试语句需要不断增加和移除代码,容易引入新的问题
- 在解决问题之后需要移除调试代码,而这些代码完全不可重用
本节介绍的技术可以缓解其中一些问题。
条件化调试代码
考虑以下包含一些调试语句的程序:
|
|
完成调试后,你要么需要删除这些调试语句,要么将它们注释掉。如果以后还需要用到,则必须重新添加它们,或取消注释。
利用预处理指令,可以很方便地在整个程序中启用或禁用调试语句。
|
|
现在,我们可以通过注释/取消注释 #define ENABLE_DEBUG 来启用或禁用调试语句。这样我们就可以重用之前添加的调试语句,在处理完问题后禁用它们,而不必从代码中实际删除。如果这是一个多文件程序,#define ENABLE_DEBUG 可以放在头文件中,被所有用到的地方引用,这样我们就可以在单个位置注释/取消注释#define,并将其效果传播到所有代码文件。
这种方法解决了必须删除调试语句以及误删代码的风险,但代价是代码变得更加混乱。它的另一个缺点是,如果你输入了错误(例如拼写错了”DEBUG”)或忘记将头文件包含在代码文件中,那么对应的文件就不会有调试语句输出。因此,尽管这比之前的版本更好,但仍有改进的余地。
使用日志记录器(Logger)
除了通过预处理器进行条件化调试之外,另一种方法是将调试信息发送到日志。日志是对已发生事件的顺序记录,通常带有时间戳。生成日志的过程称为日志记录。通常,日志会被写入磁盘上的文件(称为日志文件),以便稍后查看。大多数应用程序和操作系统都会将运行信息写入日志文件,这些文件可用于帮助诊断所发生的问题。
日志文件有几个优点。由于写入日志文件的信息与程序的正常输出是分离的,因此可以避免混合正常输出和调试输出所导致的混乱。日志文件也可以很容易地发送给其他人进行诊断——因此,如果使用你的软件的人遇到了问题,你可以要求他们将日志文件发送给你,这可能有助于提供问题所在的线索。
C++包含一个名为std::clog的输出流,用于写入日志信息。然而,默认情况下,std::clog写入的是标准错误流(与std::cerr相同)。虽然你可以将其重定向到文件,但通常更好的做法是使用现有的第三方日志库。
为了便于说明,我们将展示如何使用plog库。Plog以一组头文件的形式实现,因此很容易将其包含在你需要的任何位置,而且它是轻量级的,易于使用。
|
|
以下是来自上述代码的输出(在Logfile.txt文件中):
|
|
具体如何引用、初始化和使用日志记录器,将因你选择的库而异。
请注意,使用这种方法也不需要条件编译指令,因为大多数日志库都提供了相应的方法来控制日志的写入输出。这使得代码更容易阅读,因为条件编译行会增加许多混乱。使用plog时,可以通过将init语句更改为以下内容来临时禁用日志记录:
|
|
我们在后续的课程中不会使用plog,因此你不需要担心如何学习它。
旁白
如果要自己编译上述示例,或在自己的项目中使用plog,可以按照以下说明进行安装:
首先,获取最新的plog版本:
- 访问plog repo。
- 单击右上角的绿色Code按钮,然后选择“Download zip”
接下来,将整个存档解压缩到硬盘上的某个位置。
最后,在你的项目中,将 somewhere\plog-master\include\ 目录设置为IDE中的包含目录。
提示
在较大或对性能敏感的项目中,可以优先选择速度更快、功能更丰富的日志库,例如spdlog。