C++ #ifdef指令末尾的额外令牌

C++ #ifdef指令末尾的额外令牌,c++,c,C++,C,为什么要编译以下代码 #ifdef C++11 // ... #endif int main() {} gcc 4.8.0给了我以下警告: #ifdef指令末尾的额外令牌 根据标准,宏名称只能包含字母、数字和下划线字符 也许是因为这个 ISO/IEC 14882:2011 16.1条件包含[cpp.cond] 6按顺序检查每个指令的条件。如果评估为 false(零),跳过它控制的组:指令为 仅通过确定指令顺序的名称进行处理 跟踪嵌套条件的级别;其余的 与其他指令一样,指令的预处理标记被忽略

为什么要编译以下代码

#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

我无法正确理解这句话。

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

#ifdef
标识符新行

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

要点是:您声明的宏不是
C++11
。它实际上是
C
(参见)。预处理器将忽略
++11
部分。标识符(即
C
)后唯一允许的字符是新行,但正如hvd在§1.4的回答中所述,语法错误仅强制诊断消息,此处为警告;我认为这不是错误的唯一原因是与旧代码兼容,在旧代码中应该使用这样的名称

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

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


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

< P>关于C++是一致的,<代码>αIFIFF C++ 11 是语法错误。没有规则规定编译器必须拒绝出现语法错误的程序

1.4实施合规性[简介合规性]

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

[……]

如果一个程序违反了任何可诊断规则,或出现了本标准中描述为“有条件支持”的结构,而实现不支持该结构,则一致性实现应发出至少一条诊断消息

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

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

<代码> $PROTF“αIFIFF C++ 11 \nπNeNFF \n”gcc-STd= C++ 11 -学究错误-E-XC++ # 1 "" # 1 "" # 1 "" :1:9:错误:#ifdef指令末尾的额外令牌
我相信预处理器标识符遵循与变量标识符相同的规则,尽管大写是首选。
C++11
不起作用。这个问题应该对你有所帮助:@Eric Jablow我知道关于uu cplusplus macro,我想知道为什么这段代码在gcc 4.8.0、clang 3.2、icc 13.0.1和MSVC-11中编译对不起。我应该读得更好。也许GCC太宽容了。“我认为这不符合标准”,你确定吗?gcc 4.8.0、clang 3.2、icc 13.0.1和MSVC-11编译了该代码。是的,但这并不意味着这是标准代码。gcc、clang不是标准,他们试图遵循它。如果他们符合标准(在这一点上),他们会输出一个错误,而不是警告(除非我遗漏了什么)。你说的“然而,这不是原因”是什么意思?我认为这句引用自standard的话允许在宏名称中使用+,因此C++11可以是有效的宏名称是的,我认为当看到“实现定义”部分时。但是,标识符不是
C++11
,而是
C
,这意味着
+
不是
标识符非数字的一部分,这就是为什么我不认为这就是为什么您的代码被接受的原因。@KeithThompson即使这是无效的:“在类似宏的对象定义中,标识符和替换列表之间应留有空白。”