4

在使用 ASCII 作为其字符集的 C 编译器上,字符文字的值'??<'将等同于 的值'{',即 0x7B。在字符集没有字符的编译器上,该文字的值是多少{

在字符串文字之外,编译器可以推断出它??<应该与定义的左大括号字符具有相同的含义,即使编译器字符集没有左大括号字符也是如此。实际上,三元组的全部目的是允许使用可表示字符的序列来代替不可表示的字符。然而,规范要求三元组甚至在字符串文字中处理,这让我感到困惑。如果编译器的字符集包含一个{字符,编译器可以允许'{'表示为'??<',但字符集包含{我认为程序员没有理由不简单地使用它。如果字符集不包括{但是,这似乎是首先使用三元组的唯一原因,编译器应该用什么可表示的字符来替换??<

4

2 回答 2

5

在字符集没有 { 字符的编译器上,该文字的值是多少?

没有这样的(一致的)编译器。{基本源字符集的一部分(C99 中的5.2.1/3 ,C++11 中的[lex.charset]/1)。基本执行字符集(程序在运行时使用的)应至少包含基本源字符集的所有成员(C99中相同的5.2.1/3,C++ 中的[lex.charset]/3 11)。

正如@Mankarse 指出的那样,发明三元组不是为了支持缺少某些字符的编译器(同样,没有这样的编译器),而是为了支持人类在缺少输入这些字符所需的键的键盘上打字。

于 2014-08-26T04:32:40.673 回答
1

在考虑环境,尤其是文件时,C 标准故意变得相当模糊。对三元组及其相应字符的编码做出以下保证:

C11 (n1570) 5.1.1.2 p1(“翻译阶段”)[emph. 矿]

  1. 如有必要,物理源文件多字节字符以实​​现定义的方式映射到源字符集(为行尾指示符引入换行符)。三字母序列被相应的单字符内部表示替换

因此,三字符序列必须映射到单个字节。此单字节字符必须在基本字符集中与基本字符集中的任何其他字符不同。编译器在翻译过程中如何在内部处理它们并不是真正可观察到的行为,所以它是无关紧要的。

如果写入文本流,它可能会被转换(当我读到它时,如果底层编码没有特定字符的编码,可能会返回到三字母序列)。它可以被再次读回,如果它被认为是打印字符,则必须比较相等。同上。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 关于三元组的基本原理

于 2014-08-29T12:25:05.087 回答