7

我有一个将 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 - 或者至少需要付出巨大的努力才能使其行为合理。

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

4

1 回答 1

1

您有许多有缺陷的假设,请先纠正这些假设:

  • 事情似乎与 g++ 一起工作并不意味着 g++ 工作正常。

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

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

现在,Visual C++ 将 Windows ANSI(GetACPAPI 函数指定的编码)作为其未记录的 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 部分

于 2012-04-29T14:36:20.757 回答