2013-04-10 150 views
4

为什么下面的代码会被编译?#ifdef指令末尾的额外令牌

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

int main() {} 

GCC 4.8.0给了我以下警告:

额外的令牌在#ifdef指令

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

也许是因为这个?

ISO/IEC 14882:2011

16.1条件包含[cpp.cond]

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

我无法正确理解此引号。

+0

我相信预处理器标识符遵循与变量标识符相同的规则,尽管大写是首选。 “C++ 11”不起作用。这个SO问题应该可以帮助你:http://stackoverflow.com/questions/10717502/is-there-a-preprocessor-directive-for-detecting-c11x-support – 2013-04-10 20:01:15

+0

@Eric Jablow我知道__cplusplus宏,我想知道为什么这个代码编译在gcc 4.8.0,clang 3.2,icc 13.0.1和MSVC-11 – FrozenHeart 2013-04-10 20:26:47

+1

对不起。我应该读得更好。也许GCC太宽容了。 – 2013-04-10 20:40:59

回答

1

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

  # ifdef       标识符新行

随着正则表达式状符号,标识符是:[a-zA-Z_][a-zA-Z_0-9]* (*)

问题是:您声明的宏不是C++11。它实际上是C(见this live example)。预处理器忽略了++11部分。标识符后面的唯一允许的字符(即C)是一个新行,但正如hvd的答案中所述,来自§1.4的语法错误只会强制执行诊断消息,此处为警告;我所看到的这个而不是一个错误的唯一原因是与旧代码兼容,在这些旧代码中可能会使用这些名称。

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

我没有该标准的副本。这个答案我使用草稿n3485

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

+0

“我认为这不符合标准”你确定吗? gcc 4.8.0,clang 3.2,icc 13.0.1和MSVC-11编译此代码 – FrozenHeart 2013-04-10 20:48:36

+0

是的,但这并不意味着这是标准的。海湾合作委员会,铿锵不是标准的,他们试图*遵循它。如果他们符合标准(在这一点上),他们会输出一个错误,而不是一个警告(除非我错过了某些东西)。 – Synxis 2013-04-10 20:49:33

+0

你是什么意思“但是,这不是原因”?我认为这个标准的引用允许在宏名称中使用+,所以C++ 11可以是有效的宏名称 – FrozenHeart 2013-04-10 20:51:00

3

就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