28

我经常在C代码中使用类似对象的预处理器宏作为布尔标志来打开和关闭代码段。

例如

#define DEBUG_PRINT 1

然后像这样使用它

#if(DEBUG_PRINT == 1)
    printf("%s", "Testing");
#endif

#define但是,如果忘记将包含 的头文件包含在源代码中,则会出现问题。由于未声明宏,预处理器将其视为等于 0,并且该#if语句永远不会运行。

当忘记包含头文件时,可能会发生非预期的、不守规矩的行为。

理想情况下,我希望能够在一行中检查是否定义了宏,并检查它是否等于某个值。如果未定义,预处理器会抛出错误(或警告)。

我正在寻找类似的东西:

#if-def-and-true-else-throw-error(DEBUG_PRINT)
    ...
#endif

它就像 and 的组合#ifdef#if如果不存在,则使用#error.

我已经探索了一些途径,但是,预处理器指令不能在块内使用,据我所知,如果在语句中#define使用宏时未定义宏,则没有预处理器选项可以引发错误/警告。#if

4

6 回答 6

13

这可能不适用于一般情况(我认为您的要求没有通用解决方案),但对于您的具体示例,您可能会考虑更改以下代码序列:

#if(DEBUG_PRINT == 1)
    printf("%s", "Testing");
#endif

至:

if (DEBUG_PRINT == 1) {
    printf("%s", "Testing");
}

它不再冗长,如果DEBUG_PRINT未定义或者如果它被定义为无法与1.

于 2013-06-18T05:21:54.400 回答
12

与其直接在源文件中使用 DEBUG_PRINT ,不如将其放在头文件中:

#if !defined(DEBUG_PRINT)
    #error DEBUG_PRINT is not defined
#endif

#if DEBUG_PRINT
    #define PrintDebug([args]) [definition]
#else
    #define PrintDebug
#endif

任何使用 PrintDebug 但不包含头文件的源文件都将无法编译。

如果您需要基于 DEBUG_PRINT 编译调用 PrintDebug 以外的其他代码,请考虑使用 Michael Burr 的建议,即使用普通if而不是#if(是的,优化器不会在错误的常量测试中生成代码)。

编辑:只要您没有看起来像宏参数的逗号,您就可以将上面的 PrintDebug 概括为包含或排除任意代码:

#if !defined(IF_DEBUG)
    #error IF_DEBUG is not defined
#endif

#if IF_DEBUG
    #define IfDebug(code) code
#else
    #define IfDebug(code)
#endif

然后你可以写类似的东西

IfDebug(int count1;)  // IfDebug(int count1, count2;) won't work
IfDebug(int count2;)
...
IfDebug(count1++; count2++;)
于 2013-06-18T05:26:19.237 回答
12

#if据我所知,如果在语句中使用宏时未定义宏,则没有预处理器选项可以引发错误/警告。

这不可能是错误,因为 C 标准规定行为是合法的。来自 ISO C99 标准的第 6.10.1/3 节:

在执行了由于宏扩展和defined一元运算符而导致的所有替换之后,所有剩余的标识符都被替换为 pp-number 0...。

正如 Jim Balter 在下面的评论中指出的那样,一些编译器(例如 gcc)可能会发出警告。但是,由于替换0未识别的预处理器令牌的行为是合法的(并且在许多情况下是可取的),我希望在实践中启用此类警告会产生大量噪音。

没有办法完全按照您的意愿行事。如果要在未定义宏的情况下生成编译失败,则必须明确执行

#if !defined DEBUG_PRINT
#error DEBUG_PRINT is not defined.
#endif

对于每个关心的源文件。或者,您可以将宏转换为类似函数的宏并避免使用#if. 例如,您可以定义一个DEBUG_PRINT宏,该宏扩展为printf对调试构建的调用,但对非调试构建扩展为无。任何忽略包含定义宏的标头的文件都将无法编译。


编辑:

关于可取性,我已经多次看到代码使用:

#if ENABLE_SOME_CODE
...
#endif

代替:

#ifdef ENABLE_SOME_CODE
...
#endif

以便#define ENABLE_SOME_CODE 0禁用代码而不是启用它。

于 2013-06-18T05:06:52.387 回答
6

是的,您可以同时检查:

#if defined DEBUG  &&  DEBUG == 1
#  define D(...) printf(__VA_ARGS__)
#else
#  define D(...)
#endif

在此示例中,即使#define DEBUG 0它不等于 1,也不会打印任何内容。

你甚至可以这样做:

#if defined DEBUG  &&  DEBUG
#  define D(...) printf(__VA_ARGS__)
#else
#  define D(...)
#endif

在这里,如果你#define DEBUG 0然后D(1,2,3)也不会打印任何内容

文档

于 2018-01-23T13:52:50.603 回答
0

只需创建一个执行实际打印的宏 DEBUG_PRINT:

#define DEBUG_PRINT(n, str)    \
                               \
  if(n == 1)                   \
  {                            \
    printf("%s", str);         \
  }                            \
  else if(n == 2)              \
  {                            \
    do_something_else();       \
  }                            \
                               \
#endif


#include <stdio.h>

int main()
{
  DEBUG_PRINT(1, "testing");
}

如果未定义宏,则会出现编译器错误,因为符号无法识别。

于 2013-06-18T06:51:54.090 回答
0
#if 0 // 0/1
#define DEBUG_PRINT printf("%s", "Testing")
#else
#define DEBUG_PRINT printf("%s")
#endif

所以当“if 0”它什么都不做,当“if 1”它会执行定义的宏。

于 2015-09-29T17:24:00.637 回答