为什么使用 UTF8 在字符串文本中字符串化欧元符号不会生成 UCN

Why does stringizing an euro sign within a string literal using UTF8 not produce an UCN?

本文关键字:字符串 符号 UCN UTF8 文本 为什么      更新时间:2023-10-16

规范说在编译的第 1 阶段

不在基本源字符集 (2.3( 中的任何源文件字符都将替换为指定该字符的通用字符名称。

在第 4 阶段,它说

执行预处理指令,扩展宏调用

在第 5 阶段,我们有

字符文本或字符串文本中的每个源字符集成员,以及字符文本

或非原始字符串文本中的每个转义序列和通用字符名称,都将转换为执行字符集的相应成员

对于#运营商,我们有

在字符文本或字符串文本(包括分隔"字符(的每个"字符之前插入字符。

因此,我进行了以下测试

#define GET_UCN(X) #X
GET_UCN("€")

使用UTF-8的输入字符集(与我的文件的编码匹配(,我期望#X操作的以下预处理结果:""\u20AC""。GCC,Clang和boost.wave不会将转换为UCN,而是产生""€""。我觉得我错过了什么。你能解释一下吗?

这只是一个错误。 §2.1/1 说关于阶段 1,

(

实现可以使用任何内部编码,只要在源文件中遇到实际的扩展字符,并且在源文件中表示为通用字符名称的相同扩展字符(即使用 \uXXXX 表示法(得到等效处理。

这不是注释或脚注。C++0x 为原始字符串文本添加了一个例外,如果有的话,这可能会解决您手头的问题。

该程序清楚地演示了故障:

#include <iostream>
#define GET_UCN(X) L ## #X
int main() {
std::wcout << GET_UCN("€") << 'n' << GET_UCN("u20AC") << 'n';
}

http://ideone.com/lb9jc

由于两个字符串都很宽,因此如果编译器无法解释输入多字节序列,则需要将第一个字符串损坏为多个字符。在您给出的示例中,完全缺乏对 UTF-8 的支持可能会导致编译器盲目地回显序列。

"字符文本或非原始字符串文本中的通用字符名称将转换为执行字符集的相应成员">

曾经是

"或字符文本和字符串文本中的通用字符名称转换为执行字符集的成员">

也许你需要一个未来版本的 g++。

我不确定您从哪里获得翻译阶段 1 的引用 — C99 标准在 §5.1.1.2/1 中对翻译阶段 1 这样说:

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

因此,在这种情况下,欧元字符 €(在 UTF-8

中表示为多字节序列 E2 82 AC(映射到执行字符集,该字符集恰好也是 UTF-8,因此其表示形式保持不变。 它不会被转换为通用字符名称,因为,嗯,没有什么说它应该。

我怀疑你会发现欧元符号不满足条件Any source file character not in the basic source character set所以你引用的其余文本不适用。

使用您喜欢的二进制编辑器打开测试文件,并检查用于表示欧元登录GET_UCN("€")

的值