有没有办法检查定义的宏,它同时等于某个值

gbm*_*ter 16 c macros directive c-preprocessor

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

例如

#define DEBUG_PRINT 1
Run Code Online (Sandbox Code Playgroud)

然后像使用它一样

#if(DEBUG_PRINT == 1)
    printf("%s", "Testing");
#endif
Run Code Online (Sandbox Code Playgroud)

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

当忘记包含头文件时,可能发生非期望的,不守规矩的行为.

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

我正在寻找以下内容:

#if-def-and-true-else-throw-error(DEBUG_PRINT)
    ...
#endif
Run Code Online (Sandbox Code Playgroud)

这就像一个组合#ifdef和#if,如果它不存在,使用#error.

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

jam*_*lin 11

据我所知,如果在#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
Run Code Online (Sandbox Code Playgroud)

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

  • “这是真的,因为 C 标准规定了这种行为。” - 并不真地。该标准并没有禁止实现发布关于符合程序的诊断,在这种情况下,gcc 的 -Wundef 将做到这一点。 (2认同)

Mic*_*urr 11

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

#if(DEBUG_PRINT == 1)
    printf("%s", "Testing");
#endif
Run Code Online (Sandbox Code Playgroud)

至:

if (DEBUG_PRINT == 1) {
    printf("%s", "Testing");
}
Run Code Online (Sandbox Code Playgroud)

它不再冗长,如果DEBUG_PRINT没有定义,或者它被定义为无法比较的东西,将无法编译1.

  • 如果您的编译器在编译时没有消除`if`测试以便对两个整数文字进行简单比较(至少对于非调试版本),那么您可能希望查看另一个工具链.只要启用了某种级别的优化,几乎所有编译器都会在生成的运行时代码中省略测试(以及测试评估为false时的语句). (6认同)
  • @VoidPointer"不会以这种方式影响性能." - 当然可以.对于任何给定的实现和一组选项,它是否会是另一回事."用linux/gcc-4.7.2验证." - 您无法通过轶事验证一般声明. (4认同)

Jim*_*ter 8

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

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

#if DEBUG_PRINT
    #define PrintDebug([args]) [definition]
#else
    #define PrintDebug
#endif
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

#if IF_DEBUG
    #define IfDebug(code) code
#else
    #define IfDebug(code)
#endif
Run Code Online (Sandbox Code Playgroud)

那你可以写点东西

IfDebug(int count1;)  // IfDebug(int count1, count2;) won't work
IfDebug(int count2;)
...
IfDebug(count1++; count2++;)
Run Code Online (Sandbox Code Playgroud)


Eug*_*kov 6

是的,您可以同时检查:

#if defined DEBUG  &&  DEBUG == 1
#  define D(...) printf(__VA_ARGS__)
#else
#  define D(...)
#endif
Run Code Online (Sandbox Code Playgroud)

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

你甚至可以这样做:

#if defined DEBUG  &&  DEBUG
#  define D(...) printf(__VA_ARGS__)
#else
#  define D(...)
#endif
Run Code Online (Sandbox Code Playgroud)

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

文件