为何C标准禁止源文件以部分预处理token结尾?
背景
我正在阅读ISO C标准草案n3096,注意到§5.1.1.2 p1中的明确规定:
源文件被分解为预处理token和空白字符序列(包括注释)。**源文件不得以部分预处理token或部分注释结尾。**每个注释被替换为一个字符。换行字符被保留。除换行外的非空空白字符序列是被保留还是替换为一个空格字符,由实现定义。
该规定从C90及后续各版标准中一直存在。我有两个核心疑问:
- 为何C标准要明确禁止源文件以部分预处理token结尾?
- 该规定是否未被其他未定义行为声明覆盖?
我的理解(可能有误)
由于C标准未在其他地方定义“部分预处理token”,我参考了C++标准n4928 §5.2中的信息性脚注:
- 部分预处理token会出现在源文件以需要终止字符序列的多字符token的前半部分结尾的情况,例如缺少闭合
"或>的header-name……
根据C标准§6.4 p1对preprocessing-token的定义:
preprocessing-token:
- header-name
- identifier
- pp-number
- character-constant
- string-literal
- punctuator
- 无法归入上述类别的每个通用字符名
- 无法归入上述类别的每个非空白字符
我认为可形成“部分”状态的预处理token至少包括header-name、character-constant、string-literal以及hexadecimal-floating-constant(一种需要以binary-exponent-part结尾的pp-number)。
我假设该规定并非冗余,而是禁止了其他条款未覆盖的场景:假设非空源文件需以不属于行拼接的换行字符结尾(§5.1.1.2 p1),那么该规定描述的是源文件以不属于行拼接的换行结尾,同时也以部分预处理token结尾的情况——即翻译阶段2后,部分预处理token包含换行。但翻译阶段2后,预处理token本身并不包含换行(/*类型的注释例外,这也是禁止部分注释有实际意义的原因)。
另外我对“部分预处理token”的概念存在困惑:它显然不属于合法的预处理token,但根据preprocessing-token规则中的兜底项(无法归入其他类别的非空白字符单独作为token),似乎不存在“无效”的预处理token。
内容的提问来源于stack exchange,提问作者nore

