【问题标题】:Is there an easier way than using #ifdef in C? [duplicate]有没有比在 C 中使用 #ifdef 更简单的方法? [复制]
【发布时间】:2010-11-03 18:42:17
【问题描述】:

据我了解,assert 是 C 语言中的一个宏,据说如果您在编译时使用它但将其禁用,则不会有开销(我不知道这可能不正确)。 对我来说,问题是我想做的是将所有变量传递给我的函数并打印出该输出,但前提是我希望启用调试。这是我目前所拥有的:

int exampleFunction (int a, int b)
{
  #ifdef debugmode
  printf("a = %i, b = %i", a, b);
  #endif 
}

我想知道是否有更简单(且不那么丑陋)的方法来做这样的事情。 xdebug for php 有这个功能,我发现它在调试时为我节省了大量时间,所以我想为每个函数都这样做。

谢谢

【问题讨论】:

  • 如果定义了 NDEBUG,assert() 宏将完全禁用,因此如果在发布模式下定义,则不会产生任何开销。

标签: c debugging assertions


【解决方案1】:

试试这个:

#ifdef debugmode
#define DEBUG(cmd) cmd
#else
#define DEBUG(cmd)
#endif


DEBUG(printf("a = %i, b = %i", a, b));

现在,如果您定义了debugmode,您将获得打印语句。否则,它永远不会出现在二进制文件中。

【讨论】:

  • 遗憾的是,您只剩下一个无用的函数调用,但我 +1 是为了不那么纯粹。
  • 嗯,这给我留下了一个编译器错误:`b' undeclared (first use this function) Not sure why
  • @Kai - 未定义调试模式时没有无用的函数调用。预处理器仅用分号替换 printf,然后在可执行文件中将其转换为空。
  • 这应该适用于任何 C90 实现,这使其领先于一些仅适用于 C99 功能的解决方案。
  • 宏的非调试版本应确保编译器验证调试代码。例如,#else 子句可能是:#define DEBUG(cmd) do { if (0) cmd; while (0) -- 编译器验证命令,然后将其优化掉(如果它没有优化掉它,你会遇到比这更大的问题 - 获得一个新的编译器)。
【解决方案2】:

使用 GCC,我真的很喜欢添加每个文件:

#if 0
#define TRACE(pattern,args...)   fprintf(stderr,"%s:%s/%u" pattern "\n",__FILE__,__FUNCTION__,__LINE__,##args)
#else
#define TRACE(dummy,args...)
#endif

然后在代码中:

i++;
TRACE("i=%d",i);

i 仅在我激活文件顶部的 TRACE() 宏时才会打印。效果非常好,而且它还打印了它发生的源文件、行和函数。

【讨论】:

    【解决方案3】:
    if (MY_DEBUG_DEFINE) {
            do_debug_stuff();
    }
    

    任何半体面的编译器都会优化该块。请注意,您需要将 MY_DEBUG_DEFINE 定义为布尔值(即 0 或非 0)。

    #define MY_DEBUG_DEFINE defined(NDEBUG)
    

    如果你碰巧以最高警告级别编译,这个技巧可以避免未引用的参数

    【讨论】:

      【解决方案4】:

      使用不支持它的预处理器获取可变参数的解决方法

      #define DEBUG
      
      #ifdef DEBUG
      #define trace(args) printf args
      #else
      #define trace(args)
      #endif
      
      
      int dostuff(int value)
      {
      
      
          trace(("%d", value));
      
      }
      

      【讨论】:

        【解决方案5】:

        您可以将 PRINTF_IF_DEBUGGING 定义为

        #ifndef NDEBUG
        #define PRINTF_IF_DEBUGGING(X) printf(X)
        #else
        #define PRINTF_IF_DEBUGGING(X)
        #endif
        

        这会将#ifdefs 集中在一个地方。

        【讨论】:

        • 如果 printf 需要超过 1 个参数,这将不起作用。
        • 对。除非您使用可变参数宏,否则解决方案应该更像 #define FOO(X) printf X 以像 FOO(("%some", args)); 一样使用
        【解决方案6】:

        好吧,这里给出的 PRINT_DEBUG 类型宏的问题在于它们只允许一个参数。对于正确的 printf(),我们需要几个,但 C 宏(目前)不允许可变参数。

        因此,要实现这一目标,我们必须发挥创造力。

        #ifdef debugmode
             #define PRINTF   printf
        #else
             #define PRINTF    1 ? NULL : printf
        #endif
        

        那么当你写PRINTF("a = %i, b = %i", a, b);,在非调试模式下,它会被渲染为(有效):

         if (true) NULL;
         else printf("a = %i, b = %i", a, b);
        

        编译器很高兴,但 printf 永远不会执行,如果编译器很亮(即任何现代 C 编译器),则永远不会生成 printf() 的代码,因为编译器会识别出该路径可以永远不要被带走。

        但请注意,参数仍将被计算,因此如果它们有任何副作用(即 ++x 或函数调用),它们的代码可能会生成(但不会执行)

        【讨论】:

        • Gcc 允许多参数,请参阅我对这个问题的回答。
        • 我相信 C99 中有类似的东西。
        • 我不知道为什么人们将其标记下来---据我所知,这是唯一提供 a) 标准解决方案 b) 既不需要特定编译器也不需要特殊语法。这正是 OP 所要求的。
        【解决方案7】:

        我还会打印一些其他 C 预处理器标志,可以帮助您跟踪问题

        printf("%s:%d {a=%i, b=%i}\n", __FILE__, __LINE__, a, b);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-08-22
          • 1970-01-01
          • 1970-01-01
          • 2010-09-30
          相关资源
          最近更新 更多