#define X defined(Y) 是一个有效的 C/C++ 宏定义吗?

4
我在某个地方读到过这样的话
#define X defined(Y)

之前是无效的,但现在似乎可以工作。

这里有一个例子:

#define WIN_PLAT defined(_WIN32)

#if WIN_PLAT
#    undef  WIN_PLAT
#    define WIN_PLAT 1
#else
#    undef  WIN_PLAT
#    define WIN_PLAT 0
#endif

不行。所有写跨平台、可移植代码的人都能立刻识别#if defined(_WIN32)。不要因为想耍聪明而搞砸了。 - undefined
#if _WIN32 // #define WIN_PLAT 1 // #else // #define WIN_PLAT 0 这段代码有什么问题? - undefined
我这样做是因为我需要处理不同的编译器和不同的平台。 - undefined
但现在我正在以“标准”的方式进行。 - undefined
1
“无效”这个描述非常不准确。如果一个标记defined是由宏展开产生的(这就是你正在做的事情),那么程序的行为是未定义的。未定义行为不需要被诊断,程序表现出的任何行为都是允许的。因此,“似乎工作正常”和“在蓝月期间停止工作”都是标准下同样正确的行为。 - undefined
2个回答

7
当一个宏在#if指令中生成一个defined标记时,其行为在C标准中没有定义,根据C 2018 6.10.1 4的规定:

...如果defined标记是由此替换过程或使用defined一元运算符生成的,但不符合宏替换之前的两种指定形式之一,那么行为是未定义的...

由于行为是未定义的,编译器可以选择支持它,也可以选择不支持它。因此,一般情况下不能依赖它。
要实现#define X defined(Y),可以使用:
#if defined Y
    #define X 1
#else
    #define X 0
#endif

(这与原意不同,因为这将根据在定义宏“X”的地方是否定义了宏“Y”来设置“X”,而不是在替换它的地方。)
C++也有同样的限制。C++ 2020草案N4849 15.2 [cpp.cond] 10说:
“...如果标记“defined”是由于此替换过程或使用“defined”一元运算符而生成的,而在宏替换之前,它不匹配两种指定形式之一,行为是未定义的。”

-2
宏是文本替换,只要你将defined(Y)替换回预处理器指令,它就会起作用。但是,如果你试图在C++代码中使用它,它将不起作用。
cout << X; // error: undefined symbol 'defined'

2
宏处理通过令牌替换而非文本替换来实现。当#if指令中的宏替换结果为defined令牌时,其行为在C标准中没有定义,根据C 2018 6.10.1 4条款:“...如果defined令牌是由此替换过程生成的,或者在宏替换之前使用defined一元运算符不符合两种指定形式之一,行为是未定义的...” - undefined
1
@LuisColorado:C和C++标准明确规定,如果在#if语句中的宏替换产生了一个defined标记,其行为在标准中并没有定义。这个答案中声称它会起作用的断言并不普遍正确。 - undefined
@LuisColorado:关于“标准(C/C++)表示(正如你所提到的)宏展开之外的解释是未定义的”:不,这不是我所说的。#if defined Y是由C标准定义的,在这里defined是在宏展开之外使用的。#define X defined Y后面跟着#if X由C标准定义的,在这里defined是在宏展开中使用的。C标准规定,处理#if指令的实现不必处理由宏展开产生的defined运算符... - undefined
C和C++标准都明确声明,它们不定义在宏中使用defined操作符,并将该宏用于#if指令时的行为。 - undefined
@EricPostpischil,你现在说的(你现在说的那个)就是我想说的。依我之见,我们是同意的,所以我不完全明白你的意思。依我之见,将这个问题视为未定义(在标准中)的原因是为了避免处理可能的解释(所有这些解释都可能有效,但并不等价),这可能导致在实际代码中出现晦涩难懂的技巧。但我们都同意两个标准都将其视为未定义,所以它应该被视为未定义,你不能基于这种构造编写可移植的代码。 - undefined
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接