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

标签 c++ winapi visual-c++ unicode

我有一个程序可以将 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 输出”表明您遇到的是一点 C++来自 Visual C++ 运行时的级别帮助,它绕过流输出并使用直接控制台输出以便在控制台窗口中显示正确的字符。

当它的假设(例如 Windows ANSI 编码的窄字符串文字)不成立时,这会导致垃圾。

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

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


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

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

它太复杂了,在这里没有足够的空间来描述它(正确!),所以我不得不让你引用我的关于它的两部分博客文章系列:part 1part 2 .

关于c++ - Windows控制台下使用UTF-8输出的printf和std::ostream有什么区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10371962/

相关文章:

c++ - VS2010 缺少 ws2_32.lib。怎么办?

c++ - 使用 std::codecvt_xxx 将 C++ std::wstring 转换为 utf8

c++ - while循环c++中的负值输入

c++ - 线程完成后执行一些操作

c++ - 使用 C++ 删除 WMI 实例

c++ - MS Detours - DetourAttach 失败

c++ - 解决循环依赖的想法C++

c++ - Cython/C++ - 共享 PXD 文件中的头文件路径

c++ - 隐式转换 CString 为 char*

c - 使用 Win32 函数基于用户输入动态滚动