C11 编译.翻译阶段 #1 和 #5.通用字符名称
C11 Compilation. Phase of translation #1 and #5. Universal character names
我试图理解 C11 标准中的通用字符名称,发现 C11 标准的 N1570 草案在翻译阶段 1 和 5 以及其中 UCN 的形成和处理方面比 C++11 标准少得多。这是每个人必须说的:
翻译阶段 1
N1570 草案 C11 5.1.1.2p1.1:
如有必要,物理源文件多字节字符以实现定义的方式映射到源字符集(为行尾指示符引入换行符(。三元组序列被相应的单字符内部表示所取代。
C++11 2.2p1.1:
如有必要,物理源文件字符以实现定义的方式映射到基本源字符集(为行尾指示符引入换行符(。接受的物理源文件字符集是实现定义的。三元组序列 (2.4( 被相应的单字符内部表示所取代。不在基本源字符集 (2.3( 中的任何源文件字符都将替换为指定该字符的通用字符名称。(实现可以使用任何内部编码,只要在源文件中遇到实际的扩展字符,并且在源文件中表示为通用字符名称(即使用 \uXXXX 表示法(的相同扩展字符得到等效处理,除非此替换在原始字符串文本中还原。
翻译阶段 5
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* hellu00b0 = "hellu00b0";
-
如果在 2.中,答案是"无",那么在哪个翻译阶段,这两个标识符首先被理解为指代同一件事,尽管它们在文本上不同?
- 在 C11 中,字符/字符串文本中的 UCN 是否也在阶段 5 中转换?如果是这样,为什么在标准草案中省略这一点?
- 如何在 C11 和 C++11 中处理标识符中的 UCN(而不是已经提到的字符/字符串文本(?它们是否也在第 5 阶段转换?或者这是实现定义的东西?例如,GCC是以UCN编码的形式还是以实际的UTF-8形式打印出这样的标识符?
评论变成了答案
有趣的问题!
C标准可以保留更多的转换,因为它们是实现定义的(并且 C 没有原始字符串来混淆问题(。
- 它在 C 标准中所说的就足够了——除了它让你的问题 1 无法回答。
- 我认为,Q2 必须是"第 5 阶段",需要注意的是"令牌流是等效的"。
- Q3 严格来说是 N/A,但阶段 7 可能是答案。
- Q4 是"是",之所以这样说,是因为它提到了"转义序列",而 UCN 是转义序列。
- Q5也是"第5阶段"。
第 1 阶段和第 5 阶段中 C++11 授权的流程是否可以被视为符合 C11 的措辞(搁置原始字符串(?
我认为它们实际上是相同的;区别主要来自特定于C++的原始字面问题。一般来说,C 和 C++ 标准尽量不让事情无端地不同,特别是尝试预处理器和低级字符解析在两者中的工作方式相同(自从 C99 添加对C++ //
注释的支持以来,这更容易,但随着在 C++11 中添加原始文字,这显然变得更加困难(。
有一天,我将不得不更彻底地研究原始的文字符号及其含义。
首先,请注意,这些区别自 1998 年以来就存在;UCN于C++98年首次推出,这是一个新标准(ISO/IEC 14882,第1版:1998(,然后进入C标准的C99修订版;但是 C 委员会(以及现有的实现者,以及他们预先存在的实现(并不认为C++方法是实现这一目标的唯一方法,尤其是在极端情况下和使用比 Unicode 更小的字符集,或者只是不同;例如,在 1998 年,将映射表从任何支持的编码发送到 Unicode 的需求是 C 供应商关注的问题。
- C 标准(有意识地(避免决定这一点,让编译器选择如何继续。虽然您的推理显然发生在用于源和执行的 UTF-8 字符集的上下文中,但有大量(和预先存在的(不同的 C99/C11 编译器可用,它们使用不同的集合;委员会认为,在这个问题上,它不应该过多地限制实施者。根据我的经验,大多数编译器在实践中保持其独特性(出于性能原因(。
- 由于这种自由,一些编译器可以在阶段 1 之后使其相同(就像C++编译器一样(,而其他编译器可以在阶段 7 之前为一阶字符保留它的不同;二级字符(在字符串中(在第 5 阶段之后应该相同,假设度数字符是实现支持的扩展执行字符集的一部分。
对于其他答案,我不会在乔纳森的答案中添加任何内容。
关于您关于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(hellu00B0, "hellu00B0");
符合 C 标准的预处理器可以以与您的示例类似的方式呈现(并且大多数都这样做(,因此将具有不同的渲染;但我的印象是需要符合 C++ 的预处理器才能转换为(严格等效(
const char* hell° = "hell°" " is " ""hell\u00b0"";
const char* hellu00b0 = "hell\u00b0" " is " ""hell\u00b0"";
最后,但并非最不重要的一点是,我相信没有多少编译器完全符合这种细节水平!
- C++字符*缓冲区的大小
- HEX值到wchar_t字符(UTF-8)的转换
- 为什么 Serial.println(<char[]>);返回随机字符?
- 我的字符计数代码计算错误.为什么
- 字符串-C++后显示的随机字符
- 将Integer转换为4字节的unsined字符矢量(按大端字节顺序)
- 如何在C++中从字符串中分割字符
- 为什么msgrcv()将垃圾字符馈送到缓冲区
- 不同翻译单元中不可重载的非内联函数定义
- 指向指向字符数组的指针数组的指针
- 如何用转义符替换字符串中的所有特殊字符
- 为什么 sscanf 无法从一个字符串中读取uint64_t和字符?
- 比较字符数组
- 将字符指针十六进制转换为字符串并保存在文本文件C++中
- 从矢量<无符号字符>转换为字符* 包括垃圾数据
- 如何使用Crypto++并为RSA返回可打印的字节/字符数组
- 常量字符* 与C++的双重翻译问题
- C11 编译.翻译阶段 #1 和 #5.通用字符名称
- C++字符串字符**翻译
- C++编译.翻译阶段 #1.通用字符名称