我正在用 C++ 编写一个跨平台的应用程序。所有字符串在内部都是 UTF-8 编码的。考虑以下简化代码:
#include <string>
#include <iostream>
int main() {
std::string test = u8"Greek: αβγδ; German: Übergrößenträger";
std::cout << test;
return 0;
}
在 Unix 系统上, std::cout
8 位字符串是 UTF-8 编码的,所以这段代码可以正常工作。
然而,在 Windows 上, std::cout
8 位字符串采用 Latin-1 或类似的非 Unicode 格式(取决于代码页)。这导致以下输出:
希腊语:╬▒╬▓╬│╬┤;德语:├£bergr├Â├ƒentr├ñger
我该怎么做才能使 std::cout
在 Windows 上将 8 位字符串解释为 UTF-8?
这是我尝试过的:
#include <string>
#include <iostream>
#include <io.h>
#include <fcntl.h>
int main() {
_setmode(_fileno(stdout), _O_U8TEXT);
std::string test = u8"Greek: αβγδ; German: Übergrößenträger";
std::cout << test;
return 0;
}
我希望 _setmode
能解决问题。但是,这会在调用 operator<<
的行中导致以下断言错误:
Microsoft Visual C++ 运行时库
调试断言失败!
程序:d:\visual studio 2015\Projects\utf8test\Debug\utf8test.exe 文件:minkernel\crts\ucrt\src\appcrt\stdio\fputc.cpp 行:47
表达式: ( (_Stream.is_string_backed()) || (fn = _fileno(_Stream.public_stream()), ((_textmode_safe(fn) == __crt_lowio_text_mode::ansi) && !_tm_unicode_safe(fn))))
有关您的程序如何导致断言失败的信息,请参阅有关断言的 Visual C++ 文档。
原文由 Daniel Wolf 发布,翻译遵循 CC BY-SA 4.0 许可协议
问题不在于
std::cout
而是 Windows 控制台。 Using C-stdio you will get theü
withfputs( "\xc3\xbc", stdout );
after setting the UTF-8 codepage (either usingSetConsoleOutputCP
orchcp
) and 在 cmd 的设置中设置 Unicode 支持字体(Consolas 应该 支持超过 2000 个字符,并且有注册表黑客可以向 cmd 添加更多功能强大的字体)。如果您使用
putc('\xc3'); putc('\xbc');
一个接一个地输出一个字节,您将得到双豆腐,因为控制台将它们分别解释为非法字符。这可能是 C++ 流所做的。有关详细讨论,请参阅 Windows 控制台上的 UTF-8 输出。
对于我自己的项目,我终于实现了
std::stringbuf
转换为 Windows-1252。我真的需要完整的 Unicode 输出,但是这对你没有帮助。另一种方法是覆盖
cout
的 streambuf,使用fputs
作为实际输出:我在这里关闭了输出缓冲,以防止它干扰未完成的 UTF-8 字节序列。