【问题标题】:How to embed debugging statements in C++ using macros如何使用宏在 C++ 中嵌入调试语句
【发布时间】:2012-08-08 00:13:34
【问题描述】:

我正在编写一个程序,我想根据各种宏变量的值输出不同类型的调试信息(这样我就可以改变一个标志的值,然后导致写入不同级别的信息到屏幕上)。

例如,假设我有以下代码将有关我的程序的信息打印到屏幕上(称为 D1):

cout << "% Percentage complete: "
     << ceil((static_cast<double>(idx)/static_cast<double>(ITERATIONS))*(100.00))
     << "%" << endl;
cout << "x = [ x; ";
for(int i=0; i<space.getDimension(); i++)
    cout << visited.vec[visited.bestIndex].x[i] << "\t";
cout << "];" << endl;

现在,还假设我有以下代码,可以在屏幕上打印有关我的程序的不同信息(称为 D2):

cout << "best = [ best; "
     << visited.vec[visited.bestIndex].meanQALY() << "];\n" << endl;
space.displayConstraintsMATLAB(idx+1);

我希望能够在我的代码中的某些位置插入诸如#D1#D2 之类的语句,并让宏处理器将这些语句替换为上述代码块。

我该怎么做?

(如果宏不是理想的解决方案,我很高兴听到有关不同方法的建议。)

【问题讨论】:

  • 你的意思是#define FOO, #ifdef FOO *codeblock* #endif?
  • @DennisMeng 是的,就是这样。而且(但是)当我阅读我的代码时,我不想继续查看与调试相关的代码块。我宁愿只看到与调试相关的代码所在的语句。
  • 嗯,你可以做一个大的#define,但感觉不对...
  • 为什么不买一个带有代码折叠功能的编辑器?
  • @CarlNorum 好吧,这是一个可能的解决方案。

标签: c++ logging macros


【解决方案1】:

在我看来,您正在寻找的是一个日志记录工具。查看此线程以获取some suggestions

为什么要使用整个框架而不是宏?

问题是正确的日志记录比看起来更困难。有线程问题、会话、类和对象实例是您必须考虑的因素。日志文件缓冲、翻转和压缩日志文件也是您必须考虑的问题。您可能还想通过网络或系统日志(或两者)或数据库登录。自己正确地实现所有这些工作量很大。

宏有用吗?

当然!在我们的项目中,我们定义了一个名为 LOG 的宏,它封装了对我们的日志框架的调用(我们使用的是log4cpp)。如果有一天我们打算迁移到另一个框架,我们只需要在一个地方重新定义我们的 LOG 宏,而不是梳理整个代码库。这是因为大多数日志框架共享一个相似的接口,通常由日志级别和消息字符串组成。

【讨论】:

    【解决方案2】:

    您可以创建一个为您进行调试的宏——例如:

    #ifdef D1
    #    define DEBUG(var) //Debug 1 print implementation here
    #elif defined D2
    #    define DEBUG(var) //Debug 2 print implementation here
    #else
    #    define DEBUG(var) //No-op
    #endif
    

    否则您可以创建一个调试函数,然后在该函数内部使用#if def 语句进行类似检查,以查看您希望如何处理输入。该函数版本具有更早的类型检测,因此当您尝试打印不可处理的内容(某些自定义对象)时,它往往会以更好的方式告诉您错误。此外,如果函数是空操作(在发布模式下没有内部),那么当存在任何优化标志时,编译器将丢弃函数调用,因此您不会在发布模式下支付任何额外费用调试调用。

    对于我自己的调试调用,我通常定义一个流运算符,很像 std::cout,将所有输入转换为字符串或 char*,然后如果定义了 DEBUG 或不打印任何内容,则将它们放入调试函数。对于异常和日志记录,您可以执行具有不同严重级别(信息、警告、错误等)的类似指标。这使得在 C++ 中抛出调试代码变得像在更现代的语言 imo 中一样容易。

    【讨论】:

    • 我必须建议您同时使用这两个函数,该函数提供了良好的类型检查,而宏确保当您在发布模式下构建时,调试代码不会减慢您的程序。类似于 #ifdef DEBUG #define LOG(r) log(r) #else #define LOG(r) /*nothing*/ #endif
    • @EvanDark 对不起,如果我不清楚,我的第二个建议正是——通过#ifdef 检查实现内部结构的函数原型。当设置为 no-ops 时,将使用 opt 标志进行优化。我会更新答案以使其更清楚。
    猜你喜欢
    • 1970-01-01
    • 2021-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多