C++语言标准允许使用空宏吗?

18
根据C++11的最终委员会草案N3092,在16.3节“宏替换”中,对象式宏的定义为:
# define <标识符> <替换列表> <新行> 而函数式宏的定义为:
# define <标识符> ( <标识符列表_opt> ) <替换列表> <新行> # define <标识符> ( ... ) <替换列表> <新行> # define <标识符> ( <标识符列表> , ... ) <替换列表> <新行> 所有宏都具有替换列表(所谓的宏值),其定义如下: <替换列表>: 其中,pp-token定义如下: : 预处理记号 <预处理记号> 例如,预处理记号可以是标识符。
就我所了解的情况,带有空值的宏是被定义的。 然而,16.3-3指出:
在对象式宏的定义中,标识符和替换列表之间应该有空格。
请注意,替换列表本身不是可选的(尽管它可以具有空值)。
因此,我认为:
//well-formed (function-like macro with value)
#define f(x) (x)<NEWLINE>

//well-formed (function-like macro without value)
#define f(x)<NEWLINE>

//well-formed (function-like macro without value)
#define f(x) <NEWLINE>

//well-formed (object-like macro with value)
#define f hello<NEWLINE>

//**ill-formed** (object-like macro without value)
#define f<NEWLINE>

//well-formed (object-like macro without value)
#define f <NEWLINE>

因此,例如,所谓的“包含保护”应该采用以下形式:

#ifndef is_xyz_included<NEWLINE>
    #define is_xyz_included <NEWLINE> // NOTE THE SPACE BEFORE <NEWLINE>
#endif<NEWLINE>

我的解释有误吗?


8
这是措辞上的缺陷。继续前进,这里没有什么可看的。 - n. m.
1
@n.m.:措辞缺陷很重要。如果意图明确(就像在这种情况下一样,显然#define FOO应该是有效的),那么对于实现者或用户来说,它并不直接重要。但值得指出和修复。 - Keith Thompson
1个回答

16
我相信你的解释是正确的。因此,一个有效的包含保护必须采用你所描述的形式,并且需要有一个不是换行符的空格。不是换行符,因为根据以下内容:
【cpp】 4 预处理指令中,在介绍 # 预处理符号之后到终止换行符之前的预处理标记之间唯一允许出现的空格字符是空格和水平制表符(包括在转换阶段 3 中替换注释或可能是其他空白字符的空格)。
只有空格和制表符可以作为空格字符,这就排除了换行符是所提到的空格字符。
但是,考虑到包含保护的这种习惯用法非常普遍,以至于标准本身包含了这样一个例子,这可能是一种措辞缺陷,基于这样一个假设:宏的替换列表不能为空才能发挥任何作用。
值得一提的是,这是一个与C标准共享的措辞缺陷,就我的措辞调查而言。

空格用于分隔标记。否则它们总是可选的。这不正确吗? - R Sahu
@RSahu - 通常情况下是这样的。但在 OP 中有一种情况需要空格,即使标记可以分开。例如 #define f* 在该段落下仍然无效,即使通常情况下 f* 是两个标记而不需要空格。 - StoryTeller - Unslander Monica
谢谢。这似乎是一个合理的答案。另外需要注意的是,你引用的语句也可以在我正在阅读的N3092 16-4中找到。 - ynn
空格仅限于预处理标记之间的空格和水平制表符。因此,不在标记之间的空格(因为没有标记跟随)也可以是换行符。 - CAF
@CAF - "从预处理标记 # 的引入后,到终止换行符之前" - 这一点非常清楚。#和标识符也是预处理标记。正如OP所推测的那样,空替换列表仍然是替换列表,并且需要一个空格。 - StoryTeller - Unslander Monica

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