在考虑环境,尤其是文件时,C 标准故意变得相当模糊。对三元组及其相应字符的编码做出以下保证:
C11 (n1570) 5.1.1.2 p1(“翻译阶段”)[emph. 矿]
- 如有必要,物理源文件多字节字符以实现定义的方式映射到源字符集(为行尾指示符引入换行符)。三字母序列被相应的单字符内部表示替换。
因此,三字符序列必须映射到单个字节。此单字节字符必须在基本字符集中与基本字符集中的任何其他字符不同。编译器在翻译过程中如何在内部处理它们并不是真正可观察到的行为,所以它是无关紧要的。
如果写入文本流,它可能会被转换(当我读到它时,如果底层编码没有特定字符的编码,可能会返回到三字母序列)。它可以被再次读回,如果它被认为是打印字符,则必须比较相等。同上。7.21.2 p2:
[…] 从文本流中读取的数据必须与之前写入该流中的数据相比较,前提是: 数据仅包含打印字符和控制字符水平制表符和换行符;空格字符前面没有换行符;最后一个字符是换行符。[…]
同上。7.4 p3:
术语打印字符是指特定于区域设置的字符集的成员,每个字符在显示设备上占据一个打印位置;术语控制字符是指特定于语言环境的字符集的成员,这些字符不是打印字符。*)所有字母和数字都是打印字符。
*)在使用 7 位 US ASCII 字符集的实现中,打印字符的值介于 0x20(空格)到 0x7E(波浪号)之间;控制字符是那些值介于 0 (NUL) 到 0x1F (US) 和字符 0x7F (DEL) 的字符。
对于二进制流,同上。7.21.2 p3:
二进制流是可以透明地记录内部数据的有序字符序列。在相同的实现下,从二进制流中读取的数据应与之前写入该流的数据相比较。然而,这样的流可能具有附加到流末尾的实现定义数量的空字符。
在上面的评论中,问题出现了,如果
printf("int main(void) ??< ??>\n"); // (1)
printf("int main(void) ?\?< ?\?>\n"); // (2)
始终适用于代码生成,并且该语句的输出保证是可编译的。我找不到要求isprint('??<')
etc. (for (1)
) 甚至isprint('<')
etc (for (2)
) 返回非零的规范性参考,但是关于流的 C89 基本原理说:
需要在文本流 I/O 中保留的字符集是编写 C 程序所需的字符集;目的是标准应该允许以最大可移植的方式编写 C 翻译器。为此目的不需要退格等控制字符,因此不强制要求在文本流中处理它们。
当'??<'
etc. 被写入二进制流时,它必须映射到单个字节,按原样打印,是唯一的并且可与任何其他基本字符区分开来,并且'??<'
在读回时比较等于。
相关:C89 关于三元组的基本原理。