C++ u8 文字 - Windows 上的意外编码
Posted
技术标签:
【中文标题】C++ u8 文字 - Windows 上的意外编码【英文标题】:C++ u8 literal - unexpected encoding on Windows 【发布时间】:2019-11-26 07:49:26 【问题描述】:我确定我在这里遗漏了一些东西,但我正在将常规字符串文字(在 utf8 编码文档中)的内容与 u8 字符串文字进行比较,并且在 Windows 上,u8 编码文字不包含预期的 utf8在 Linux 上编码数据。
详情:
cpp文件是utf8编码的 C++17 已启用 在 Windows 上使用 vs 2019 编译 在 Linux 上使用 gcc 9.2.1 编译代码如下:
#include <iostream>
#include <string>
struct HexCharStruct
unsigned char c;
HexCharStruct(unsigned char _c) : c(_c)
;
inline std::ostream& operator<<(std::ostream& o, const HexCharStruct& hs)
return (o << std::hex << (int)hs.c);
inline HexCharStruct hex(unsigned char _c)
return HexCharStruct(_c);
int main( int argc, char** argv )
std::string s1 = "????";
std::string s2 = u8"????";
std::cout << "s1: ";
for (const char& c : s1)
std::cout << hex(c) << " ";
std::cout << "\ns2: ";
for (const char& c : s2)
std::cout << hex(c) << " ";
return 0;
以下是我运行此命令时在 Windows 和 Linux 上为 s1 和 s2 打印的十六进制值:
s1(Windows):f0 9f 8e 82 s1 (Linux): f0 9f 8e 82 s2 (Windows): c3 b0 c5 b8 c5 bd e2 80 9a s2 (Linux): f0 9f 8e 82???? 的 utf8 十六进制值是 f0 9f 8e 82,所以除了 Windows 上的 s2 之外,一切都如预期的那样。谁能解释一下?
【问题讨论】:
看起来像是utf8字符串的双重utf8转换。 是的。字符 U+00F0 以 UTF-8 编码,字节 0xC3 0xB0。您的编译器将 u8 字符串视为 CP-1252 或 Latin-1 或其他单字节字符编码的内容,并将其转换为 UTF-8。 在我看来,UTF-8 支持在 Linux 上的g++
中不再是问题,但在 Windows 上的 VS 中仍然是一个问题。对我有用的东西(不管每个系统):将 UTF-8 序列编码为八进制序列:例如"\303\260"
用于 U+00F0(并且默默地假设 std::string
永远不会包含除 UTF-8 之外的任何内容)。这在过去和现在都有效。 (但是,我年纪大了,不灵活地采用新功能......);-)
尝试将源文件保存为带有 BOM 的 UTF-8。如果没有 BOM,编译器将采用系统默认代码页。或者,对于足够新的 MSVC 版本,使用 `/utf-8' option
【参考方案1】:
Microsoft 编译器假定源代码是 ANSI 编码的,这取决于所使用的 Windows 的本地化版本。在美国和西欧 Windows 上,编码假定为 Windows-1252
。
当编译器假定Windows-1252
时,它会解码源中以错误编码编码的UTF-8
字节并认为它是四个Windows-1252
字符,然后将那些 字符编码为UTF- 8.快速演示(Python):
>>> '?'.encode('utf8') # bytes in the file
b'\xf0\x9f\x8e\x82'
>>> b'\xf0\x9f\x8e\x82'.decode('Windows-1252') # What the compiler reads.
'🎂'
>>> '🎂'.encode('utf8') # What the compiler generates for u8 string.
b'\xc3\xb0\xc5\xb8\xc5\xbd\xe2\x80\x9a'
要使用 UTF-8 源代码,有两个选项是使用带有 BOM 的 UTF-8 对源代码进行编码,或者添加 /utf-8
编译器开关。
【讨论】:
感谢您的回答。只是继续讨论一下。因此,在这种情况下,编译器假设 u8-literals 是 Windows-1252 编码的,但正确地假设所有普通字符串文字都是 utf8 编码的。因此,如果文档在 Windows 上是 utf8 编码并且使用包含 utf8 字符的文字,则假定正确的编码,但如果您想使用 u8 文字说明符,则需要 /utf-8 编译器标志。似乎是一个错误,编译器标志只是在规避它。 @aatwo 不,在您的示例中,s1
将包含源中编码的字节。编译器在读取源代码时采用编码,并在创建"..."
字符串时采用相同的编码。 L"..."
或 u8"..."
字符串必须使用假定或指定的源编码将源字节解码为 Unicode 代码点,然后将这些代码点分别编码为 UTF-16/UTF-32 (Windows/Linux) 或 UTF-8 ,因此如果源编码不正确,则会得到不正确的结果。以上是关于C++ u8 文字 - Windows 上的意外编码的主要内容,如果未能解决你的问题,请参考以下文章
patchValue 错误上的 Angular PrimeNG p-calendar 反应形式 位置 2 处的意外文字
Windows 10 上的 vs 代码中的“liveSass.command.watchMySass 未找到”和“扩展主机意外终止”