如何测试预处理器符号是否#define'd但没有值?

时间:2010-09-23 18:44:59

标签: c++ visual-c++ c-preprocessor

使用C ++预处理程序指令,是否可以测试是否已定义预处理程序符号但没有值?这样的事情:

#define MYVARIABLE
#if !defined(MYVARIABLE) || #MYVARIABLE == ""
... blablabla ...
#endif

编辑:我这样做的原因是因为我正在处理的项目应该通过/DMYSTR=$(MYENVSTR)从环境中获取一个字符串,并且此字符串可能为空。如果用户忘记定义此字符串,我想确保项目无法编译。

10 个答案:

答案 0 :(得分:35)

Soma宏魔法:

#define DO_EXPAND(VAL)  VAL ## 1
#define EXPAND(VAL)     DO_EXPAND(VAL)

#if !defined(MYVARIABLE) || (EXPAND(MYVARIABLE) == 1)

Only here if MYVARIABLE is not defined
OR MYVARIABLE is the empty string

#endif

请注意,如果在命令行中定义MYVARIABLE,则默认值为1

g++ -DMYVARIABLE <file>

这里MYVARIABLE的值是1

g++ -DMYVARIABLE= <file>

这里MYVARIABLE的值是空字符串

引用问题解决了:

#define DO_QUOTE(X)        #X
#define QUOTE(X)           DO_QUOTE(X)

#define MY_QUOTED_VAR      QUOTE(MYVARIABLE)

std::string x = MY_QUOTED_VAR;
std::string p = QUOTE(MYVARIABLE);

答案 1 :(得分:10)

  

如果用户忘记定义此字符串,我想确保项目无法编译。

虽然我在之前的构建步骤中检查了这一点,但您可以在编译时执行此操作。使用Boost简洁:

#define A "a"
#define B
BOOST_STATIC_ASSERT(sizeof(BOOST_STRINGIZE(A)) > 1); // succeeds
BOOST_STATIC_ASSERT(sizeof(BOOST_STRINGIZE(B)) > 1); // fails

答案 2 :(得分:9)

我没有看到这个问题的解决方案,但我很惊讶它没有被普遍使用 。它似乎适用于Xcode Objc。区分“无值定义”和“定义集0”

#define TRACE
#if defined(TRACE) && (7-TRACE-7 == 14)
#error TRACE is defined with no value
#endif

答案 3 :(得分:3)

您可以使用BOOST_PP_IS_EMPTY宏,如下所示:

#include <boost/preprocessor/facilities/is_empty.hpp>

#define MYVARIABLE
#if !defined(MYVARIABLE) || !BOOST_PP_IS_EMPTY(MYVARIABLE)
    // ... blablabla ...
#endif

这对我有用。我将添加此宏未记录,因此请谨慎使用。

来源:preprocessor-missing-IS-EMPTY-documentation

答案 4 :(得分:3)

必须扩大Mehrad的答案才能使其发挥作用。还有他的评论

  

/ * MYVARI(A)BLE在这里未定义* /

不正确;为了测试未定义的变量,有一个简单的测试#ifndef MYVARIABLE

然而,经过这样的测试,他的表达导致原始问题的正确解决方案。我测试了这个代码的工作原理,对于宏MYVARIABLE的未定义,定义但是空的非空值:

#ifndef MYVARIABLE
    /* MYVARIABLE is undefined here */
#elif ~(~MYVARIABLE + 0) == 0 && ~(~MYVARIABLE + 1) == 1
    /* MYVARIABLE is defined with no value here */
#else
    /* MYVARIABLE is defined here */
#endif

#elif语句~(~MYVARIABLE + 0) == 0 && ~(~MYVARIABLE + 1) == 1的工作原理如下:

  • 当定义MYVARIABLE但是为空时,它会扩展为~(~+0) == 0 && ~(~+1) == 1,这会导致0==0 && 1==1(双重否定~~是身份运算符)。
  • MYVARIABLE定义为数值(例如n)时,它会扩展为~(~n+0)==0 && ~(~n+1)==1。在&&的左侧,表达式~(~n+0)==0的计算结果为n==0。但是对于n==0,右侧评估为~(~0+1)==1,其中~0为-1到~(-1+1)==1,然后是~0==1,最后是-1==1,这显然是假的。
  • MYVARIABLE被定义为非数字值时,预编译器会将所有未知符号减少为0,并且我们再次获得n == 0的前一种情况。

我的完整测试代码(另存为文件test.c):

#include <stdio.h>

int main() {
    printf("MYVARIABLE is "
#ifndef MYVARIABLE
     "undefined"
#elif ~(~MYVARIABLE + 0) == 0 && ~(~MYVARIABLE + 1) == 1
     "defined without a value"
#else 
     "defined with this value : %i", MYVARIABLE
#endif
    );
    printf("\n");
}

使用GNU预处理器 cpp ,您可以尝试查看生成的代码:

# undefined
cpp test.c
#defined without a value
cpp -DMYVARIABLE= test.c
#defined wit an implicit value 1
cpp -DMYVARIABLE test.c
#defined wit an explicit value 1
cpp -DMYVARIABLE=1 test.c
#defined wit an explicit value a
cpp -DMYVARIABLE=a test.c

或编译和执行的输出(在某些linux下)

$ gcc -o test test.c ; ./test
MYVARIABLE is undefined
$ gcc -DMYVARIABLE= -o test test.c ; ./test
MYVARIABLE is defined without a value
$ gcc -DMYVARIABLE -o test test.c ; ./test
MYVARIABLE is defined with this value : 1
$ gcc -DMYVARIABLE=1 -o test test.c ; ./test
MYVARIABLE is defined with this value : 1
$ gcc -DMYVARIABLE=a -o test test.c ; ./test
test.c: In function ‘main’:
<command-line>:0:12: error: ‘a’ undeclared (first use in this function)
...

在上一次运行中,MYVARIABLE定义为'a',错误不是宏定义中的错误;宏正确导致最后一种情况,“使用此值定义...”。但是这个值是'a','a'没有在代码中定义,编译器或过程必须发出信号。

这样,最后一个案例就是为什么原始问题的意图非常危险的一个很好的例子:通过宏,用户可以在要编译的代码中引入任何程序行序列。检查是否未引入此类代码,需要在有效值上检查宏。可能需要一个完整的脚本,而不是将此任务留给预处理。在这种情况下,在预处理中检查它的用途是什么?

答案 5 :(得分:2)

我不认为这可以做到。话虽如此,我认为没有必要。当您创建预处理器#define符号时,您应该建立一个约定,您可以将其定义为1或0以便在#if中使用,或者将其留空。

答案 6 :(得分:2)

您不能,因为预处理器只能检查数值。预处理器语法不包含字符串比较。

答案 7 :(得分:0)

仅适用于整数宏...

你可以使用没有额外宏的hack:

#if ~(~MYVARIABLE + 0) == 0 && ~(~MYVARIABLE + 1) == 1
/* MYVARIBLE is undefined here */
#endif

答案 8 :(得分:0)

#if MYVARIABLE==0 我的答案必须是至少30个字符,所以应该这样做!

答案 9 :(得分:0)

在相关说明中,我们经常想检查宏是否未定义,是否,或者具有非零值 :

#if ! defined(MYVARIABLE)
  // UNDEFINED:  MYVARIABLE is undefined
#elif ~ MYVARIABLE + 1
  // TRUE:       MYVARIABLE is defined and is empty or nonzero
#else
  // FALSE:      MYVARIABLE is defined and is zero
#endif

这是如何工作的?

  • 如果 MYVARIABLE 为空,则 ~ + 1 计算为非零(真)
  • 如果 MYVARIABLE 为非零(例如 1),则 ~ 1 + 1 的计算结果为非零(真)
  • 如果 MYVARIABLE 为零,则 ~ 0 + 1 的计算结果为零 (false)

此方法适用于 MYVARIABLE 的任何整数值。当 MYVARIABLE 是另一个宏的名称时,将使用该宏的值,正如预期的那样。

请注意,如果您只想检查 MYVARIABLE 作为编译时标志是否已启用(已定义且为空或非零):

#if defined(MYVARIABLE) && ~ MYVARIABLE + 1
  // the MYVARIABLE feature is enabled
#endif