C++ 高级调试策略:条件调试与日志记录技术

在上一课(3.4 — 基本调试策略)中,我们开始探索如何手动调试问题。在那节课中,我们对使用语句打印调试文本提出了一些批评:

  • 调试语句会使代码变得杂乱无章
  • 调试语句会使程序的输出变得杂乱无章
  • 添加和移除调试语句需要修改代码,这可能会引入新的错误
  • 调试语句在使用完毕后必须被移除,这使得它们不可重复使用

我们可以缓解其中的一些问题。在本课中,我们将探讨一些基本技术来实现这一点。

调试策略 #1:条件化调试代码

考虑以下包含一些调试语句的程序:

#include <iostream>

int getUserInput()
{
    std::cerr << "getUserInput() called\n";
    std::cout << "Enter a number: ";
    int x{};
    std::cin >> x;
    return x;
}

int main()
{
    std::cerr << "main() called\n";
    int x{ getUserInput() };
    std::cout << "You entered: " << x << '\n';

    return 0;
}

使用预处理器实现条件调试

当你完成调试语句后,你将需要删除它们或将它们注释掉。然后如果你想以后再次使用它们,你将不得不将它们添加回去或取消注释。以下是一个更好的方法:

#include <iostream>

#define ENABLE_DEBUG // 注释掉以禁用调试

int getUserInput()
{
#ifdef ENABLE_DEBUG
    std::cerr << "getUserInput() called\n";
#endif
    std::cout << "Enter a number: ";
    int x{};
    std::cin >> x;
    return x;
}

int main()
{
#ifdef ENABLE_DEBUG
    std::cerr << "main() called\n";
#endif
    int x{ getUserInput() };
    std::cout << "You entered: " << x << '\n';

    return 0;
}

提示:在多文件程序中,#define ENABLE_DEBUG 应该放在一个共享的头文件中,这样可以在一个位置统一控制所有文件的调试输出。

调试策略 #2:使用日志记录器

日志记录的优势

日志记录提供了以下优点:

  • 调试信息与正常输出分离
  • 日志文件可以轻松分享给其他开发者
  • 包含时间戳和其他有用的元数据
  • 可以长期保存以供后续分析

使用 plog 日志记录器示例

#include <plog/Log.h> // 第 1 步:包含日志记录器头文件
#include <plog/Initializers/RollingFileInitializer.h>
#include <iostream>

int getUserInput()
{
    PLOGD << "getUserInput() called"; // PLOGD 由 plog 库定义

    std::cout << "Enter a number: ";
    int x{};
    std::cin >> x;
    return x;
}

int main()
{
    plog::init(plog::debug, "Logfile.txt"); // 第 2 步:初始化日志记录器

    PLOGD << "main() called"; // 第 3 步:像写入控制台一样输出到日志

    int x{ getUserInput() };
    std::cout << "You entered: " << x << '\n';

    return 0;
}

日志输出示例

2018-12-26 20:03:33.295 DEBUG [4752] [main@19] main() called
2018-12-26 20:03:33.296 DEBUG [4752] [getUserInput@7] getUserInput() called

安装和配置 plog

要使用 plog,请按以下步骤操作:

  1. 从 plog 仓库下载最新版本
  2. 解压文件到本地目录
  3. 在 IDE 中设置包含目录:somewhere\plog-master\include\

提示:对于性能敏感的项目,建议考虑使用更快、功能更丰富的日志记录器,如 spdlog。

禁用日志输出

要临时禁用日志记录,只需修改初始化语句:

plog::init(plog::none, "Logfile.txt"); // 使用 plog::none 级别来禁用大多数日志输出

关注公众号,回复"cpp-tutorial"

可领取价值199元的C++学习资料

公众号二维码

扫描上方二维码或搜索"cpp-tutorial"