printf 和 std::ostream 在 Windows 控制台下使用 UTF-8 输出有什么区别

What is the different between printf & std::ostream under windows console using UTF-8 output

本文关键字:UTF-8 输出 什么 区别 控制台 std ostream printf Windows      更新时间:2023-10-16

我有一个将 UTF-8 字符串打印到控制台的程序:

#include <stdio.h>
int main()
{
    printf("Мир Peace Ειρήνηn");
    return 0;   
}

我将控制台配置为使用True Type字体(Lucida控制台(,定义UTF-8代码页(chcp 65001(使用MinGW GCC和Visual Studio 2010编译此程序,它运行良好,我看到:输出:

Мир Peace Ειρήνη

我使用std::cout做同样的事情

#include <iostream>
int main()
{
    std::cout << "Мир Peace Ειρήνηn" ;
    return 0;   
}

这完全可以正常工作,如上所述使用MinGW GCC,但使用Visual Studio 2010我得到正方形,比正方形更多(每个非ASCII字母两个(。

如果我使用重定向运行程序test >test.txt我会得到完美的 UTF-8 输出在文件中。

这两项测试都是在Windows 7上完成的。

问题:

  1. Visual Studio 标准库中的 printf 和 std::cout 在处理输出流方面有什么区别 - 显然其中一个有效而另一个无效?
  2. 如何解决这个问题?

真实答案:

简而言之:你搞砸了 - std::cout并不能真正使用 MSVC + UTF-8 - 或者至少需要付出巨大的努力才能使其表现合理。

长篇:阅读答案中引用的两篇文章。

你有一些有缺陷的假设,请先纠正这些假设:

  • 似乎可以使用 g++ 并不意味着 g++ 可以正常工作。

  • Visual Studio不是一个编译器,它是一个支持多种语言和编译器的IDE。

  • Visual C++ 的标准库需要修复的结论是正确的,但导致该结论的推理是错误的。此外,g++标准库也需要修复。更不用说 g++ 编译器本身了。

现在,Visual C++将Windows ANSI(由GetACP API函数指定的编码(作为其未记录的C++执行字符集。即使您的源代码是带有 BOM 的 UTF-8,窄字符串最终也会转换为 Windows ANSI。如果在编译时在您的计算机上是一个包含所有非 ASCII 字符的代码页,那么确定,否则窄字符串将出现乱码。因此,如果不提及源代码编码和 Windows ANSI 代码页,测试结果的描述就严重不完整

但无论如何,"如果我使用重定向运行程序test >test.txt我在文件中得到完美的 UTF-8 输出"表明您遇到的是来自 Visual C++ 运行时的一些C++级帮助,它绕过流输出并使用直接控制台输出以获得控制台窗口中显示的正确字符。

当其假设(如 Windows ANSI 编码的窄字符串文本(不成立时,这有助于产生垃圾。

这也意味着当您重定向流时,效果会神秘地消失。然后,运行时库检测到流转到文件,并关闭直接控制台输出功能。您不能保证获得原始原始字节值,但显然您做到了,这是运气不好,因为它掩盖了问题。

顺便说一下,Windows 控制台中的代码页 65001 在实践中不可用。许多程序只是崩溃。包括例如 more .


获取正确输出的一种方法是直接使用 Windows API 级别,直接使用控制台输出。

使用 C++ 流获取正确的输出要复杂得多。

是如此复杂,以至于这里没有空间来描述它(正确!(,所以我不得不向你推荐我的两部分博客文章系列:第 1 部分和第 2 部分。