C++ u8文本应该如何工作?
难以理解u8文本的语义,或者更确切地说,难以理解g++4.8.1上的结果C++ u8文本应该如何工作?,c++,c++11,C++,C++11,难以理解u8文本的语义,或者更确切地说,难以理解g++4.8.1上的结果 const std::string utf8 = u8"åäö"; // or some other extended ASCII characters assert( utf8.size() == 3); 这是我的期望: const std::string utf8 = u8"åäö"; // or some other extended ASCII characters assert( utf8.size() >
const std::string utf8 = u8"åäö"; // or some other extended ASCII characters
assert( utf8.size() == 3);
这是我的期望:
const std::string utf8 = u8"åäö"; // or some other extended ASCII characters
assert( utf8.size() > 3);
这是g++4.8.1上的结果
const std::string utf8 = u8"åäö"; // or some other extended ASCII characters
assert( utf8.size() == 3);
- 源文件是ISO-8859(-1)
- 我们使用以下编译器指令:-m64-std=c++11-pthread-O3-fpic
const std::string utf8 = u8"åäö"; // or some other extended ASCII characters
assert( utf8.size() > 3);
assert( utf8 == "åäö");
- 编译器指令:g++-m64-std=c++11-pthread-O3-finput charset=ISO8859-1
- 尝试了从iconv定义的其他一些字符集,例如:ISO_8859-1等等
我现在比以前更困惑了…前缀
u8
实际上只是指“编译此代码时,从该文本生成UTF-8字符串”。它没有说明编译器应该如何解释源文件中的文本
因此,有几个因素在起作用:
u8
前缀将其指定为UTF-8-finput charset
采用哪种源代码编码,或者您可以将源代码编码为UTF-8,或者您可以使用字符串文本中的\uxxx
转义序列(\u00E5
而不是å
)
编辑:
为了澄清一点,当您在源代码中指定带有u8
前缀的字符串文字时,您告诉编译器“无论您在读取源文本时使用哪种编码,请在将其写入目标文件时将其转换为UTF-8”。您没有说明源文本应该如何解释。这取决于编译器的决定(可能基于您传递给它的标志,可能基于进程的环境,或者可能只是使用硬编码的默认值)
如果源文本中的字符串包含字节0xc5、0xe4、0xf6,并且您告诉它“源文本编码为ISO-8859”,那么编译器将识别“字符串由字符组成”“。它将看到u8
前缀,并将这些字符转换为UTF-8,将字节序列0xc3、0xa5、0xc3、0xa4、0xc3、0xb6写入目标文件。在这种情况下,您将得到一个有效的UTF-8编码文本字符串,其中包含字符“åäö”的UTF-8表示形式
但是,如果源文本中的字符串包含相同的字节,并且您让编译器相信源文本编码为UTF-8,那么编译器可以做两件事(取决于实现:
- 它可能尝试将字节解析为UTF-8,在这种情况下,它将识别“这不是有效的UTF-8序列”,并发出错误。这就是Clang所做的
- 或者,它可能会说“好的,我这里有3个字节,我被告知它们构成一个有效的UTF-8字符串。我会抓住它们,看看会发生什么”。然后,当它应该将字符串写入对象文件时,它会“好的,我有以前的3个字节,它们被标记为UTF-8。这里的
前缀意味着我应该把这个字符串写为UTF-8。酷,那就不需要做转换了。我只写这3个字节,我就完成了。”这就是GCC所做的u8
u8
前缀与您的问题无关。这只是告诉编译器从“读取字符串时使用的任何编码”转换为UTF-8“。但即使在进行此转换之前,字符串已被乱码,因为字节对应于ISO-8859字符数据,但编译器认为它们是UTF-8(因为您没有告诉它)
您看到的问题只是编译器在从源文件读取字符串文字时不知道使用哪种编码
您注意到的另一件事是,没有前缀的“传统”字符串文字将使用编译器喜欢的任何编码进行编码。
u8
前缀(以及相应的UTF-16和UTF-32前缀)精确地让你精确地指定你希望编译器编写输出的编码。普通的前缀较少文字根本不指定一个编码,留给编译器来决定一个。 为了说明这个讨论,这里有一些例子。让我们考虑代码:
int main() {
std::cout << "åäö\n";
}
换句话说,每个“grapheme集群”有两个字节(根据unicode术语,即
% ./a.out | od -txC
0000000 e5 e4 f6 0a
% objdump -s -j .rodata a.out
a.out: file format elf64-x86-64
Contents of section .rodata:
400870 01000200 00e5e4f6 0a00 ..........
% ./a.out | od -txC
0000000 c3 a5 c3 a4 c3 b6 0a
% ./a.out | od -txC
0000000 e5 e4 f6 0a
int main() {
std::cout << u8"åäö\n";
}
% ./a.out | od -txC
0000000 c3 a5 c3 a4 c3 b6 0a
% ./a.out | od -txC
0000000 c3 a5 c3 a4 c3 b6 0a