[英]Why unicode char is stored as UTF-8 in std::string and UTF-16/32 in wchar_t?
我有一小段代码:
#include <locale.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
wchar_t widec('€');
wchar_t widecl(L'€');
std::string tc("€");
int main(int argc, char *argv[])
{
printf("printf as hex - std::string tc(\"€\") = %x %x %x\n\r", tc.c_str()[0], tc.c_str()[1], tc.c_str()[2]);
printf("printf as hex - wchar_t widec('€') = %x\n\r", widec);
printf("printf as hex - wchar_t widecl(L'€') = %x\n\r", widecl);
return 0;
}
那输出:
printf as hex - std::string tc("€") = ffffffe2 ffffff82 ffffffac
printf as hex - wchar_t widec('€') = e282ac
printf as hex - wchar_t widecl(L'€') = 20ac
我不明白两件事。
为什么tc.c_str()
(它的[0]
, [1]
和[2]
索引是准确的)打印为UTF-8,看起来像UTF-16/32,具有前导FF字节?
为什么初始化相同的wchar_t
变量会产生不同的输出,具体取决于是否使用了L
前缀,即。 使用它似乎产生UTF-16/32内容和没有L
前缀的UTF-8,为什么会这样?
没有显式符号说明符的char
是有signed
或unsigned
,具体取决于编译器。 该标准没有规定默认类型,它是编译器供应商的选择。
将char
传递给print()
会将值从8位扩展到32位。 然后%x
打印该32位值的位,默认忽略前导零(除非您在%x
上使用长度说明符来保留它们)。 8位值如何扩展到32位取决于其实际类型。
在你的情况下,额外的f
你请参阅s是由于char
值是符号扩展 。 0xEx
, 0x8x
和0xAx
都是1,因此1用于在扩展期间填充高24位。 这意味着您的编译器将char
实现为signed
类型,并将值扩展为signed int
。 您可以手动将char
值类型转换为unsigned
以强制它们为零扩展 :
printf("printf as hex - std::string tc(\\"€\\") = %x %x %x\\n", (unsigned char) tc[0], (unsigned char) tc[1], (unsigned char) tc[2]);
(注意我删除了c_str()
的使用,在你的例子中没有必要)
没有任何前缀的'€'
和"€"
的解释取决于源文件保存为的编码,以及编译器配置为运行的编码。
如果您的源代码文件以UTF-8保存,那么未加前缀的'€'
和"€"
文字可能是UTF-8的唯一方法是(强制使用UTF-8文字,您可以在C +中使用u8
前缀+11及以后)。 以不同的编码保存文件,您将看到不同的结果。 然后将该解释的结果按原样分配给tc
,并按原样编码为widec
的wchar_t
。
另一方面, L
前缀强制编译器将L'€'
为宽文字而不是窄文字,因此不应该如何解释它。 它知道文字是Unicode,因此它确定了Unicode代码点值,然后在widecl
其编码为wchar_t
值( wchar_t
在Windows上为16位,在其他平台上为32位)。 €
的Unicode代码点是U+20AC EURO SIGN
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.