我试图理解C11标准中的通用字符名称,发现C11标准的N1570草案在翻译阶段1和5以及内部UCN的形成和处理方面比C ++ 11标准的细节要少得多。他们。这是每个人都要说的:
N1570草案C11 5.1.1.2p1.1:
物理源文件多字节字符以实现定义的方式映射到源字符集(如果需要,引入行尾指示符的换行符)。 Trigraph序列由相应的单字符内部表示替换。
C ++ 11 2.2p1.1:
物理源文件字符以实现定义的方式映射到基本源字符集(如果需要,引入行尾指示符的换行符)。接受的物理源文件字符集是实现定义的。 Trigraph序列(2.4)由相应的单字符内部表示代替。不在基本源字符集(2.3)中的任何源文件字符将替换为指定该字符的通用字符名称。 (实现可以使用任何内部编码,只要在源文件中遇到实际扩展字符,并且在源文件中表示为与通用字符名称相同的扩展字符(即,使用\ uXXXX表示法),处理等效,除非在原始字符串文字中还原此替换。)
N1570草案C11 5.1.1.2p1.5:
字符常量和字符串文字中的每个源字符集成员和转义序列都将转换为执行字符集的相应成员; [...]
C ++ 2.2p1.5:
转换字符文字或字符串文字中的每个源字符集成员以及字符文字或非原始字符串文字中的每个转义序列和通用字符名称到执行字符集的相应成员; [...]
(强调增加差异)
在C ++ 11标准中,非常清楚的是,不在基本源字符集中的源文件字符被转换为UCN,并且它们被完全视为在同一个地方的UCN ,唯一的例外是原始字符串。 C11也是如此吗?当C11编译器看到一个多字节的UTF-8字符,例如°
时,它是否也会在阶段1中将其转换为\u00b0
,并将其视为\u00b0
已出现在那里代替
以不同的方式,在翻译阶段结束时(如果有的话),下面的代码片段是第一次在C11中转换为文本等效的形式?
const char* hell° = "hell°";
和
const char* hell\u00b0 = "hell\u00b0";
如果在2.中,答案是“无”,那么在翻译阶段,这两个标识符首先被理解为指的是同一个东西,尽管文本上有所不同?
答案 0 :(得分:2)
评论变成了答案
有趣的问题!
C标准可以使更多的转换没有说明,因为它们是实现定义的(并且C没有原始字符串来混淆问题)。
第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供应商的当务之急。
对于其他答案,我不会向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\"";
最后,但并非最不重要的是,我相信没有太多的编译器完全符合这一级别的细节!