C11编译。翻译阶段#1和#5。通用角色名称

时间:2013-09-24 03:59:21

标签: c++ c c++11 unicode c11

我试图理解C11标准中的通用字符名称,发现C11标准的N1570草案在翻译阶段1和5以及内部UCN的形成和处理方面比C ++ 11标准的细节要少得多。他们。这是每个人都要说的:

翻译阶段1

N1570草案C11 5.1.1.2p1.1:

  

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

C ++ 11 2.2p1.1:

  

物理源文件字符以实现定义的方式映射到基本源字符集(如果需要,引入行尾指示符的换行符)。接受的物理源文件字符集是实现定义的。 Trigraph序列(2.4)由相应的单字符内部表示代替。不在基本源字符集(2.3)中的任何源文件字符将替换为指定该字符的通用字符名称。 (实现可以使用任何内部编码,只要在源文件中遇到实际扩展字符,并且在源文件中表示为与通用字符名称相同的扩展字符(即,使用\ uXXXX表示法),处理等效,除非在原始字符串文字中还原此替换。)

翻译阶段5

N1570草案C11 5.1.1.2p1.5:

  

字符常量和字符串文字中的每个源字符集成员和转义序列都将转换为执行字符集的相应成员; [...]

C ++ 2.2p1.5:

  

转换字符文字或字符串文字中的每个源字符集成员以及字符文字或非原始字符串文字中的每个转义序列和通用字符名称到执行字符集的相应成员; [...]

(强调增加差异)

问题

  1. 在C ++ 11标准中,非常清楚的是,不在基本源字符集中的源文件字符被转换为UCN,并且它们被完全视为在同一个地方的UCN ,唯一的例外是原始字符串。 C11也是如此吗?当C11编译器看到一个多字节的UTF-8字符,例如°时,它是否也会在阶段1中将其转换为\u00b0,并将其视为\u00b0已出现在那里代替

  2. 以不同的方式,在翻译阶段结束时(如果有的话),下面的代码片段是第一次在C11中转换为文本等效的形式?

    const char* hell° = "hell°";
    

    const char* hell\u00b0 = "hell\u00b0";
    
  3. 如果在2.中,答案是“无”,那么在翻译阶段,这两个标识符首先被理解为指的是同一个东西,尽管文本上有所不同?

  4. 在C11中,字符/字符串文字中的UCN是否也在第5阶段转换?如果是这样,为什么要从标准草案中省略这一点?
  5. 如何在C11和C ++ 11中处理标识符中的UCN(与已提及的字符/字符串文字相对)?它们是否也在第5阶段转换?或者这是实现定义的东西?例如,GCC是否以UCN编码的形式或实际的UTF-8打印出这些标识符?

2 个答案:

答案 0 :(得分:2)

评论变成了答案

有趣的问题!

C标准可以使更多的转换没有说明,因为它们是实现定义的(并且C没有原始字符串来混淆问题)。

  1. 它在C标准中所说的就足够了 - 除了它让你的问题1无法回答。
  2. 我认为Q2必须是'第5阶段',并且有关于'令牌流等效'的警告。
  3. Q3严格来说是N / A,但第7阶段可能就是答案。
  4. Q4是'是',它是这样说的,因为它提到了'逃逸序列'而UCN是逃逸序列。
  5. Q5也是'第5阶段'。
  6.   

    第1阶段和第5阶段的C ++ 11强制进程能否在C11的措辞中被认为是合规的(放弃原始字符串)?

    我认为它们实际上是一样的;差异主要来自于特定于C ++的原始文字问题。通常,C和C ++标准尽量不要让事情有所不同,特别是尝试预处理器的工作方式和在两者中解析相同的低级字符(由于C99增加了对C ++的支持{{1注释,但在将原始文字添加到C ++ 11时显然变得更难了。

    有一天,我将不得不更彻底地研究原始文字符号及其含义。

答案 1 :(得分:1)

首先,请注意,自1998年以来存在这些区别; UCN首先在C ++ 98中引入,这是一个新标准(ISO / IEC 14882,第1版:1998),然后进入C标准的C99版本;但C委员会(以及现有的实施者,以及他们已有的实现)并不认为C ++方式是实现这一技巧的唯一方法,特别是对于角落案例和使用比Unicode更小的字符集,或者只是不同的;例如,将映射表从所支持的编码发送到Unicode的要求是1998年C供应商的当务之急。

  1. C标准(有意识地)避免决定这一点,让编译器选择如何继续。虽然您的推理显然与源和执行使用的UTF-8字符集的上下文有关,但是有大量(和预先存在的)不同的C99 / C11编译器可供使用,它们使用不同的集合;委员会认为不应该在这个问题上过多地限制实施者。根据我的经验,大多数编译器在实践中保持不同(出于性能原因。)
  2. 由于这种自由,一些编译器可以在第1阶段之后使它们完全相同(就像C ++编译器一样),而其他编译器可以在第7阶段为第一级角色留下不同之处;假设度数字符是实现支持的扩展执行字符集的一部分,第二阶段字符(在字符串中)应该在第5阶段之后相同。
  3. 对于其他答案,我不会向Jonathan's添加任何内容。

    关于您关于符合标准C的C ++更确定性过程的其他问题,显然这是一个目标;如果你发现另一个角落情况(符合C ++ 11标准的预处理器不符合C99和C11标准),那么你应该考虑向WG14委员会询问潜在的缺陷。

    显然,情况恰恰相反:可以编写一个处理符合C99 / C11但不符合C ++标准的UCN的预处理器;

    最明显的区别
    #define str(t) #t
    #define str_is(x, y)  const char * x = y " is " str(y)
    str_is(hell°,      "hell°");
    str_is(hell\u00B0, "hell\u00B0");
    

    一个C兼容的预处理器可以以与您的示例类似的方式呈现(并且大多数都这样做),因此,将具有不同的呈现;但我认为需要符合C ++标准的预处理器才能转换为(严格等效的)

    const char* hell°      = "hell°"       " is " "\"hell\\u00b0\"";
    const char* hell\u00b0 = "hell\\u00b0" " is " "\"hell\\u00b0\"";
    

    最后,但并非最不重要的是,我相信没有太多的编译器完全符合这一级别的细节!