包含不可表示字符的三字符的字符文字的含义

时间:2014-08-26 04:18:21

标签: c language-lawyer trigraphs

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

在字符串文字之外,编译器可以推断??<应该具有相同的含义,因为开放括号字符被定义为具有,即使编译器字符集不具有& #39; t有一个开括号的角色。实际上,三字母的整个目的是允许使用可表示字符的序列来代替不可表示的字符。该规范要求三字符甚至在字符串文字中处理,然而,这令我感到困惑。如果编译器的字符集包含{字符,编译器可以允许'{'表示为'??<',但字符集包括{我看不到程序员不会简单地使用它的原因。但是,如果字符集不包含{,这似乎是首先使用三字符串的唯一原因,那么编译器应该使用什么可表示的字符替换??<? / p>

2 个答案:

答案 0 :(得分:5)

  

对于字符集没有{字符?

的编译器,该文字的值是多少?

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

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

答案 1 :(得分:1)

当涉及对环境的考虑,特别是对文件的考虑时,C标准故意变得相当模糊。以下保证有关三字母及其相应字符的编码:

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

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

因此,必须将三字符序列映射到单个字节。此单字节字符必须位于与基本字符集中的任何其他字符不同的基本字符集中。

表示编译器在翻译过程中如何在内部处理它们并不是真正可观察到的行为,因此无关紧要。

如果写入文本流,它可能会被转换(当我读取它时,如果基础编码没有某个特定字符的编码,可能会返回到三字符序列)。它可以再次回读,如果它被认为是打印字符,必须比较相等。同上。 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('??<')等((1))或甚至isprint('<')等((2))返回非零的规范性引用,但{{3说:

  

需要在文本流I / O中保留的字符集是编写C程序所需的字符集;意图是标准应该允许以最便携的方式编写C语言翻译器。为此,不需要诸如退格之类的控制字符,因此不需要在文本流中处理它们。

'??<'等写入二进制流时,它必须映射到单个字节,如此打印,是唯一的并且可以与任何其他基本字符区分开来,并且比较等于'??<'回读时。


相关:the C89 rationale about streams