#ifdef指令末尾的额外令牌

时间:2013-04-10 19:48:05

标签: c++ c

为什么以下代码会编译?

#ifdef C++11
// ...
#endif

int main() {}

gcc 4.8.0给了我以下警告:

  #if> #ifdef指令结束时的额外令牌

根据标准,宏名称只能包含字母,数字和下划线字符。

也许是因为这个?

ISO / IEC 14882:2011

  

16.1条件包含[cpp.cond]

     

6按顺序检查每个指令的条件。如果评估为   false(零),它控制的组被跳过:指令是   仅通过按顺序确定指令的名称进行处理   跟踪嵌套条件的级别;剩下的   指令的预处理令牌被忽略,另一个则被忽略   预处理组中的令牌。只有第一组控制   处理条件计算结果为真(非零)。如果没有   条件评估为真,并且有一个#else指令,即   由#else控制的组被处理;没有#else指令,   所有组,直到#endif被跳过.151

我无法正确理解这句话。

2 个答案:

答案 0 :(得分:3)

就C ++而言,#ifdef C++11是语法错误。没有规则说编译器必须拒绝具有语法错误的程序。

  

1.4实施合规性[intro.compliance]

     

可诊断规则集包含本国际标准中的所有语法和语义规则,但那些包含“无需诊断”的明确表示法或描述为“未定义行为”的规则除外。

     

[...]

     

如果程序包含违反任何可诊断规则或本标准中描述的构造的发生,如果实现不支持该构造,则符合条件的实现应发出至少一条诊断消息。 / p>

警告是诊断消息。编译器完全有权继续成功编译程序,只要它们确保它们向您显示一条诊断消息即可。由于编制者历来接受这样的指令,并且接受这些指令并不与标准的要求相冲突,他们继续这样做。

至少就GCC而言,您可以要求使用-pedantic-errors选项使所有标准要求的诊断成为硬错误。

$ printf "#ifdef C++11\n#endif\n" | gcc -std=c++11 -pedantic-errors -E -x c++ -
# 1 "<stdin>"
# 1 "<command-line>"
# 1 "<stdin>"
<stdin>:1:9: error: extra tokens at end of #ifdef directive

答案 1 :(得分:1)

#ifdef定义如下(取自§16.1)

  

# ifdef 标识符新行

使用类似regexp的表示法,标识符为:[a-zA-Z_][a-zA-Z_0-9]*(*)

重点是:您声明的宏不是C++11 。它实际上是C(见this live example)。预处理器忽略++11部分。标识符后面唯一允许的字符(C)是一个新行,但正如hvd的回答所述,从§1.4开始,语法错误只强制诊断消息,这里是警告;我认为这个而不是错误的唯一原因是与旧代码兼容,这些名称应该被使用。

另外:引用解释了#ifdef / #elif / #else / #endif如何协同工作,而不是指定条件的方式。

我没有标准的副本。我使用草稿n3485作为答案。

(*)可以在标识符中包含实现定义的字符,但这不会影响您的问题。请注意,变量,类名,宏,...都遵循相同的标识符规则。