除了pp-number的实例之外,还有哪些典型的、属于有效预处理记号、但却是无效记号的例子?

编程语言 2026-07-09

除了pp-number的实例(例如 0xe+1),有哪些是有效的预处理标记的典型例子,但它们实际是无效标记?

额外问题:所有标记都是有效的预处理标记吗?(换句话说:是否存在任何有效标记,不能通过“预处理标记 => 标记”转换得到?)

解决方案

根据C 2024 6.4.1,preprocessing-token 是以下之一:

  • header-name
  • identifier
  • pp-number
  • character-constant
  • string-literal
  • punctuator
  • 每个不可归入上述任一项的通用字符名称
  • 每个不可为上述任一项的非空格字符

任何 header-name 若不匹配 string-literal 的形式,例如 <stdlib.h>,都是一个预处理标记,但不是有效标记。然而,header-name 仅在某些预处理指令和表达式中被识别,并不会保留到翻译阶段7(将预处理标记转换为标记时),因此也不会把 header-name 转换为标记。

一个 identifiertoken 的一个选项,因此任何作为 identifierpreprocessing-token 都是一个有效的 token(尽管其中一些在阶段7 会被转换为 keyword)。

如问题所述,一些 pp-number 预处理标记不是有效标记。

character-constantconstant 的一个选项,而 constant 又是 token 的一个选项,且 string-literalpunctuator 也是 token 的选项,因此每一个这样的实例都是一个有效的 token

剩下的最後两项, universaI character names和无法归入上述六种类型之一的非空格字符。6.4.1指出一个 '" 可能匹配最后一类(因为它们并非数字常量的一部分,如新的 0b1101'1111'0010'0010,并且不能形成字符常量或字符串字面量——要么缺少结束符,要么在字符常量或字符串字面量的语法上有无效之处),因此它们会成为一个预处理标记但不是有效标记的实例。

在我看来,这两类中的任何预处理标记都不能成为有效的标记。如果universal character name或非空格字符能够成为标识符的一部分,那么我们就会得到一个 identifier 作为 preprocessing-token。因此这个预处理标记不可能成为 identifier 类型的 token。同样,它也不能成为 keywordstring-literal、或 punctuator。在 token 的选项中,剩下的只有 constant。查看这些的文法,它们要么是一个 character-constant(与前述排除方式相同),要么是一个 enumeration-constant(它是一个 identifier,已排除),要么是一个 predefined-constantfalsetrue、或 nullptr,都不匹配这两类中的任一项),要么是一个 integer-constantfloating-constant,而它们都以数字开头。

所以,不能成为有效标记的预处理标记是:

  • 任何不符合 string-literal 形式的 header-name,尽管这在将预处理标记转换为标记的过程中从未发生过。
  • 任何不符合 integer-constantfloating-constant 形式的 pp-constant
  • 任何不能归入前六种类型之一的通用字符名称。
  • 任何不能归入前六种类型之一的非空格字符,包括一个单独的 '"

关于额外的问题,对于一个 token 的每一个选项,在 preprocessing-token 中都存在一个等于它或比它更广的前身形式。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章