【问题标题】:How to write an 'if' condition that compiles only when DEBUG is #defined?如何编写仅在#defined DEBUG 时编译的“if”条件?
【发布时间】:2010-06-23 16:59:24
【问题描述】:

在为“if-condition”编写宏时需要一些帮助,该宏仅在#define 指令定义了 DEBUG 标志时编译。

这是一个说明我想要什么的例子。第一段代码显示了使用#ifdef 编写if 条件的常用方法。

#ifdef DEBUG
if( rv == false )
{
     string errorStr = "error in return value" ;
     cout << errorStr << endl ;
     throw( Exception(errorStr) ) ;
}

我想写成类似下面这样的方式:

DEBUG_IF( rv==false )
{
     same code as above
}

这似乎很简单,但我在定义一个可以做到这一点的宏时遇到了麻烦。如果有人以前遇到过这种情况,请提供帮助。

谢谢。

【问题讨论】:

  • 仅供参考,发布代码时,选择它并单击10101 图标以获取正确的格式。
  • 我想知道为什么是-1。对我来说似乎是一个不错的问题。
  • @jalf:因为它含糊不清。而且因为我的代表不是 5 的倍数,这让我很烦恼。 :)
  • #if 0 as a define的可能重复
  • 这可能是一个副本,但这个标题更好。

标签: c++ macros


【解决方案1】:

试试:

#ifdef DEBUG
  #define DEBUG_IF(x) if(x)
#else
  #define DEBUG_IF(x) if(false)
#endif

现在这将与您现在所拥有的完全相同,因为当使用此方法时,if 块内的代码仍会被编译,尽管它永远不会run 当DEBUG 没有定义时,可能会被优化掉。相比之下,在您的原始示例中,代码被预处理器消除,甚至从未编译过。

【讨论】:

  • “以后可能会被优化”->“被优化”。没有办法低估它并使 OP 怀疑编译器执行微不足道的优化。
  • 地球上每个可能的标志集下的每个编译器总是会消除死代码?我对此表示怀疑。
  • 无论如何,我的观点是if 块内的代码在使用此宏时必须是有效的、可编译的代码,因为即使消除它也会编译,而直接使用#ifdef 代码可能包含只要DEBUG 保持未定义就不会被检测到的错误。
  • 我可能会建议“将可能”而不是“可能”。
  • @Tyler:视情况而定。通常,如果性能或内存占用有任何问题,您将使用至少具有最少优化的编译器。具有最小优化的编译器通常会消除该代码。在大多数情况下,这没什么好担心的。例外情况是在一些非常晦涩的系统上使用非常糟糕的编译器,而且这种情况并不多。
【解决方案2】:

我想这就是你要找的东西:

#include <iostream>

#ifdef DEBUG
#define DEBUG_IF(cond) if(cond)
#else
#define DEBUG_IF(cond) if(false)
#endif

int main(int argc, char** argv)
{
  DEBUG_IF(argc > 1)
  {
     std::cout << "In debug mode and at least one argument given" << std::endl;
  }
  else
  {
    std::cout << "Not in debug mode or no arguments given" << std::endl;
  }
}

在命令行运行它,带或不带参数,无论是否使用-DDEBUG 编译,以证明它按预期工作。

【讨论】:

  • 您不希望 ELSE 块始终与 #DEBUG 宏的状态一起包含/排除吗? OP对此尚不清楚。
【解决方案3】:

恕我直言,最好的方法是

#ifdef DEBUG
if(blah){
    dostuff();
}
#endif

【讨论】:

    【解决方案4】:

    您是否希望 if 是有条件的,以便在 Release 中代码无条件运行? (正如标题所暗示的那样。)或者您是否希望整个块都是有条件的? (所以它 Release 没有阻塞。)您在等效代码中缺少#endif,因此无法分辨。

    对于前者,你可以这样:

    #ifdef DEBUG
        #define DEBUG_IF(x) if (x)
    #else
        #define DEBUG_IF(x) if (false)
    #endif
    

    块中的代码将被编译,但被编译器丢弃,因为它是死代码。如果您只想更改条件,请执行以下操作:

    #ifdef DEBUG
        #define DEBUG_IF(x) if (x)
    #else
        #define DEBUG_IF(x)
    #endif
    

    没有DEBUG,整个条件句就不存在了。修正你的问题,明确你想要什么。

    【讨论】:

    • 这是错误的。如果在没有 DEBUG 符号的情况下将 DEBUG_IF(x) 定义为空白,则 DEBUG_IF(foo) { bar } 将变为始终执行的 { bar }
    • 没有DEBUG,就好像条件总是true,即块将被执行。这不是 OP 要求的。
    • 那么,我并不清楚 OP 的问题。 DEBUG_IF( rv==false ) 只向我建议一件事......
    • 我理解的问题是“我如何制作一个宏,以便如果DEBUG 被定义并且条件为真,则块执行?”因为这描述了他的第一个 sn-p 的行为。
    • @Tyler:是吗?他的第一个 sn-p 不是真正的代码。如果是这样,您是如何设法提取真实代码的? #endif 可以去任何地方。由于他的第二个示例仅包含带有宏的 if,因此我以此为理由相信您打算在第一个示例中的 if 之后结束 if,并且与标题中的问题相匹配。他应该编辑和澄清,以便我们知道。
    【解决方案5】:

    我个人会使用#ifdef DEBUG 路由而不是代码混淆 DEBUG_IF 宏方法。最好编写清晰的代码,不会将代码隐藏在某些宏后面。

    如果你真的想走宏观路线,我会不理会if,而是专注于条件本身,例如

    #ifdef DEBUG
    # define DEBUG_CONDITION(x) x
    #else
    # define DEBUG_CONDITION(x) false
    #endif  /* DEBUG */
    
    if (DEBUG_CONDITION(rv == false))
    {
       ...
    }
    

    这种方法仍然存在一些混淆,但恕我直言,它比建议的 DEBUG_IF() 宏更容易接受,因为它保留了 C/C++ 语法。

    我相信大多数(如果不是全部)编译器会简单地优化在非DEBUG 情况下由if(false) 产生的死代码(例如,相当于if(0))。但是,可以想象,使用这种方法以及您描述的 DEBUG_IF() 方法,某些编译器可能会发出“死代码”警告。

    【讨论】:

      【解决方案6】:

      由于 Kelly 指出的原因,我不建议使用 DEBUG_IF 类型的宏。

      DEBUG_IF(x)
      {
          // debugging code
      }
      else
      {
          // release code (should be executed for both debug and release)
      }
      

      看到这里的逻辑错误了吗?除非是仅发布代码,否则应始终执行发布代码,但使用 DEBUG_IF 宏会很容易犯这种错误。写出来可能会很麻烦,但我认为这是最清晰、最不容易混淆的方式。如果您确实使用它,我建议您完全避免使用它。

      DEBUG_CONDITION 宏也是如此。

      if (DEBUG_CONDITION(x) )
      {
          // debugging code
      }
      else
      {
          // oops, this never gets executed in debug builds
      }
      

      与仅调试代码相比,仅发布代码非常罕见,因此此类事件通常是逻辑错误。当我开始使用 C++ 时,我想简写所有内容,但多年来我已经了解到,尤其是与团队合作时,通常最好按预期写出来。力求在逻辑上做到简洁,但你必须小心不要越过将代码步骤减少到混淆边界的界限。

      调试一个充满像这样的 DEBUG_IF/DEBUG_CONDITION 宏的大型系统的想法让我头疼不已。

      【讨论】:

        【解决方案7】:

        这里有点晚了,但我想知道简单地定义一个常量是否比定义一个函数更优雅:

        #ifdef DEBUG
            #define IS_IN_DEBUG true
        #else
            #define IS_IN_DEBUG false
        #endif
        
        if ( IS_IN_DEBUG ) {
          // do something
        }
        

        这不是更容易阅读吗?对此有什么想法吗?

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-12-23
          • 2016-10-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-09-18
          相关资源
          最近更新 更多