C 是否有一种方法既可以检查宏是否已定义,又可以检查它是否同时等于某个值

C 是否有一种方法既可以检查宏是否已定义,又可以检查它是否同时等于某个值,c,macros,c-preprocessor,directive,C,Macros,C Preprocessor,Directive,我经常在C代码中使用类似对象的预处理器宏作为布尔标志来打开和关闭代码部分 比如说 #define DEBUG_PRINT 1 然后像这样使用它 #if(DEBUG_PRINT == 1) printf("%s", "Testing"); #endif 但是,如果包含#define的头文件忘记包含在源代码中,则会出现问题。由于未声明宏,预处理器将其视为等于0,并且#if语句从不运行 当忘记包含头文件时,可能会发生非预期的、难以控制的行为。 理想情况下,我希望能够在一行中检查宏是否已定义

我经常在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
它就像是
#ifdef
#if
的组合,如果它不存在,则使用
#error

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

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

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

由于宏扩展和定义的
一元
已执行操作,所有剩余标识符均替换为pp编号
0

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

没有办法做到你想要的。如果要在未定义宏的情况下生成编译失败,则必须显式执行此操作

#if !defined DEBUG_PRINT
#error DEBUG_PRINT is not defined.
#endif
对于每个关心的源文件。或者,您可以将宏转换为类似宏的函数,并避免使用
#if
。例如,您可以定义一个
DEBUG\u PRINT
宏,该宏对调试生成展开为
printf
调用,但对非调试生成展开为零。任何忽略包含定义宏的头的文件都将无法编译


编辑:

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

#if ENABLE_SOME_CODE
...
#endif
而不是:

#ifdef ENABLE_SOME_CODE
...
#endif

<> P> > <代码> >定义Enaby-AthoLoad 0 禁用代码而不是启用它。

< P>这对一般情况可能不起作用(我不认为有什么通用的解决方案),但是对于您的具体示例,您可以考虑更改这个代码序列:

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


如果未定义
DEBUG\u PRINT
,或者定义为无法与
1

进行比较,而不是直接在源文件中使用DEBUG\u 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的打印代码来编译PrimeDebug,请考虑使用Michael Burr的“使用纯代码”的建议,如果而不是<代码> >如果(是的,优化器不会在假常量测试中生成代码)。 编辑: 只要没有类似宏参数的逗号,就可以将上面的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++;)

只需创建一个执行实际打印的宏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");
}
#定义调试打印(n,str)\
\
如果(n==1)\
{                            \
printf(“%s”,str)\
}                            \
else如果(n==2)\
{                            \
做点别的事吧\
}                            \
\
#恩迪夫
#包括
int main()
{
调试打印(1,“测试”);
}
如果未定义宏,则会出现编译器错误,因为无法识别符号

#if 0 // 0/1
#define DEBUG_PRINT printf("%s", "Testing")
#else
#define DEBUG_PRINT printf("%s")
#endif

因此,当“if 0”时,它将不执行任何操作,当“if 1”时,它将执行定义的宏。

是,您可以同时选中这两个选项:

#if defined DEBUG  &&  DEBUG == 1
#  define D(...) printf(__VA_ARGS__)
#else
#  define D(...)
#endif
在本例中,即使定义调试0,但它不等于1,因此不会打印任何内容

您甚至可以这样做:

#if defined DEBUG  &&  DEBUG
#  define D(...) printf(__VA_ARGS__)
#else
#  define D(...)
#endif
在这里,如果您定义调试0,然后
D(1,2,3)
,也不会打印任何内容


编译器不能把你从所有事情中拯救出来……没错。然后,您需要将
print
函数包装到宏或其他函数中,而不是在所有调用位置包装它。然后,您可以将错误生成代码整合到一个地方,而不是尝试将其散布到整个项目中。您可能很容易忘记使用
\if def和true else抛出错误(DEBUG\u PRINT)
,而不是
\if DEBUG\u PRINT==1
,因此,即使存在此功能,它也不会实现任何有用的功能。如果在头文件中定义了PrintDebug(这是它的逻辑位置),那么如果不包含头文件,代码将不会编译。
gcc
有一个选项(
-Wundef
)在指令
#if
中计算未定义的标识符时生成警告。啊……好主意。我首先想到,不,这不好,引入的额外执行时间呢(我来自嵌入式背景)!但这又是一个sim卡
#if defined DEBUG  &&  DEBUG
#  define D(...) printf(__VA_ARGS__)
#else
#  define D(...)
#endif