6

为什么下面的代码会编译?

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

int main() {}

gcc 4.8.0 给了我以下警告:

#ifdef 指令末尾的额外标记

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

也许是因为这个?

ISO/IEC 14882:2011

16.1 条件包含 [cpp.cond]

6 按顺序检查每个指令的条件。如果它的计算结果为假(零),则跳过它控制的组:指令仅通过确定指令的名称进行处理,以跟踪嵌套条件的级别;其余指令的预处理标记被忽略,组中的其他预处理标记也是如此。仅处理其控制条件评估为真(非零)的第一组。如果没有一个条件为真,并且有 #else 指令,则处理由 #else 控制的组;如果缺少 #else 指令,则跳过 #endif 之前的所有组。151

我无法正确理解这句话。

4

2 回答 2

4

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

1.4 实施合规性 [intro.compliance]

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

[...]

如果程序包含违反任何可诊断规则或出现在本标准中描述为“有条件支持”的构造,而实现不支持该构造,则符合要求的实现应发出至少一个诊断消息。

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

至少就 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
于 2013-04-10T21:24:19.907 回答
1

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

# ifdef      标识符换行

使用类似正则表达式的表示法,标识符是:[a-zA-Z_][a-zA-Z_0-9]*(*)

关键是:您声明的宏不是C++11。事实上C(见这个活生生的例子)。该++11部分被预处理器忽略。标识符(即C)之后唯一允许的字符是换行符,但正如 hvd 的回答中所说,从 §1.4 开始,语法错误只会强制发出诊断消息,这里是警告;我看到这个而不是错误的唯一原因是与旧代码兼容,其中已经使用了这些名称。

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

我没有标准的副本。我使用草稿n3485来回答这个问题。

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

于 2013-04-10T20:46:50.467 回答