在 Windows 中使用 C++ 将 Unicode 输出到控制台

Posted

技术标签:

【中文标题】在 Windows 中使用 C++ 将 Unicode 输出到控制台【英文标题】:Output Unicode to console Using C++, in Windows 【发布时间】:2011-02-20 09:32:39 【问题描述】:

我还在学习 C++,所以请耐心等待我和我草率的代码。我使用的编译器是 Dev C++。我希望能够使用 cout 将 Unicode 字符输出到控制台。每当我尝试这样的事情时:

#include <iostream>

int main()

    std::cout << "Hello World!\n";
    std::cout << "Blah blah blah some gibberish unicode: ĐĄßĞĝ\n";
    system("PAUSE");
    return 0;

它向控制台输出奇怪的字符,例如 µA■Gg。为什么会这样,我怎样才能显示 ĐĄßĞĝ?或者这在 Windows 上是不可能的吗?

【问题讨论】:

只是一个评论:不要使用系统(“暂停”),这是非常糟糕的做法。你可以用 cin 代替。 gidnetwork.com/b-61.html 天哪,人们是怎么做到的?为什么每个新手都会被 Dev C++ 吸引? 5 年前那块垃圾是马车,你猜怎么着?它仍然是今天,因为从那时起就没有维护过。有这么多的免费编译器和IDE。为什么哦,为什么初学者坚持选择唯一一个绝对废话,缺乏基本功能,从未工作过,并且漏洞百出并且默认带有史前编译器的版本? @jalf:如果你链接到一个这样好的、免费的编译器和 IDE,你的咆哮会更有用。 @nmuntz:我同意system("pause");,但您链接到的文章同样糟糕。一方面,cin.get() 通常 not 就足够了。暂停的作用要大得多,最突出的是清理输入缓冲区。在 C++ 中以可移植、可靠的方式做到这一点非常非常困难。事实上,我知道的两种解决方案(忽略 1-cin.rdbuf()-&gt;in_avail(),2-numeric_limits&lt;streamsize&gt;::max())在不同的当前编译器上都失败了(它们编译但不起作用)。链接页面的其余部分是稻草人的论点。谁在乎暂停是昂贵的?它只调用一次! @Joachim:很公平。微软有 Visual C++ Express,它包括一个优秀的编译器和免费的 IDE。这几乎是 Windows C++ 开发的事实标准。 GCC 是一流的跨平台编译器,经常与 Code::Blocks 或 Eclipse IDE 一起使用。 【参考方案1】:

std::wcout 呢?

#include <iostream>

int main() 
    std::wcout << L"Hello World!" << std::endl;
    return 0;

这是标准的宽字符输出流。

不过,正如 Adrian 所指出的,这并没有解决 cmd 默认情况下不处理 Unicode 输出的事实。这可以通过手动配置控制台来解决,如 Adrian 的回答中所述:

cmd 开头,带有/u 参数; 调用chcp 65001更改输出格式; 并在控制台中设置 unicode 字体(如 Lucida Console Unicode)。

您也可以尝试使用_setmode(_fileno(stdout), _O_U16TEXT);,这需要fcntl.hio.h(如this answer 中所述,并在this blog post 中记录)。

【讨论】:

这并没有解决控制台通常处于 ANSI 或 OEM 模式这一事实。 这基本上是对的,但是...cmd 默认情况下会处理 Unicode 输出到控制台,但在重定向到文件时不会。使用/u 也可以将Unicode 输出到重定向文件。在这两种情况下,“Unicode”都意味着UTF-16,就像在 Windows 上一样。 chcp 65001ANSI 代码页设置为UTF-8,这与宽字符、wcoutcmd /u 无关。您无需将代码页设置为 UTF-8 即可输出 UTF16!此外,WriteFile() API 在chcp 65001 下被破坏。如果您想输出超出 ANSI 代码页的字符,_setmode() 调用非常重要且必需! @Adrian:控制台没有 ANSI 或 OEM 模式。它只有一个 ANSI 代码页,默认情况下是 OEM 代码页,例如 437 或 850。但您不必通过此代码页打印。所有 Windows 文本 API 都有一个A 版本和一个W 版本。 A 用于通过代码页的 ANSI,W 用于不通过代码页但直接处理 UTF-16 Unicode 的“宽”。两者都始终存在,没有要求,甚至没有切换“模式”的可能性。 +1 建议您在控制台中设置“unicode 字体”。那对我来说是缺失的部分。我认为单独执行 chcp 65001 会启用 unicode 字体。【参考方案2】:

我不确定 Windows XP 是否会完全支持您的需求。要使用命令控制台启用 Unicode,您必须做三件事:

    使用cmd /u 启动命令窗口。 /u 表示您的程序将输出 Unicode。 使用 chcp 65001 表示您想使用 UTF-8 而不是代码页之一。 选择字形覆盖率更高的字体。较新版本的 Windows 中的命令窗口提供Lucida Console Unicode。我的 XP 盒子有一个名为 Lucida Console 的子集。它没有非常广泛的曲目,但如果您只是想显示一些重音字符,它应该足够了。

【讨论】:

+1 用于使用 chcp 65001 - 这可以解决问题。 (来自 cmd /? : /U 使内部命令输出到管道或文件为 Unicode。) 1. /u 仅表示内置命令在重定向时将输出 UTF-16 而不是 ANSI。这对您自己的代码或未重定向的输出没有任何意义。 2. 由于WriteFile() API 中的错误导致它返回错误值,chcp 65001 无法与 UTF-8 控制台输出一起正常工作。此 API 由标准 C 库函数(例如 printf())调用,任何检查返回代码的函数都可能失败或导致不可预知的行为。 3. 字体建议是正确的,是 Windows 恕我直言的愚蠢失败。【参考方案3】:

您可以使用 the open-source fmt library 便携式打印 Unicode 文本,包括在 Windows 上,例如:

#include <fmt/core.h>

int main() 
  fmt::print("Blah blah blah some gibberish unicode: ĐĄßĞĝ\n");

输出:

Blah blah blah some gibberish unicode: ĐĄßĞĝ

这需要使用 MSVC 中的 /utf-8 编译器选项进行编译。

我不推荐使用wcout,因为它是不可移植的,例如:

std::wcout << L"Blah blah blah some gibberish unicode: ĐĄßĞĝ\n";

将在 macOS 或 Linux (https://godbolt.org/z/z81jbb) 上错误地打印 ĐĄßĞĝ 部分:

Blah blah blah some gibberish unicode: ??ss??

如果不更改代码页,甚至无法在 Windows 上运行:

Blah blah blah some gibberish unicode:

免责声明:我是 fmt 的作者。

【讨论】:

/utf-8 是做什么的? Windows 内部不是 UTF-16 吗?在运行时转换为 UTF-16 不是效率低下吗?整个 Win32 都是 UTF-16,你怎么解决这个问题? 从文档 (docs.microsoft.com/en-us/cpp/build/reference/…) 我读到,如果您不指定 /utf-8,它将使用用户区域设置代码页,这意味着您的程序可能会根据区域设置显示不同编译程序的用户,并且可能在执行期间也在语言环境中(哎呀!)我不再使用 Windows,所以请谨慎使用,但链接可能会对您有所帮助。 /utf-8 将源和执行编码设置为 UTF-8。从技术上讲,这是不必要的,但如果您使用的是旧版编码,fmt 不会进行转码。转码仅在写入控制台时发生,与呈现文本所需的时间相比可以忽略不计。当输出被重定向时,没有转码,这是fmtwcout 相比的另一个优势。 @vitaut 感谢您的广泛评论。一个发人深省的问题:在这种情况下,为什么不在fmt 中默认使用UTF-8,让处理遗留编码的人加倍努力(当切换到fmt 时)而不是其他所有人? @AyxanHaqverdili,好问题。我正在考虑在下一个主要版本中将默认值切换为 UTF-8,并选择退出旧行为。【参考方案4】:

在 Linux 中,我可以天真地做:

std::cout << "ΐ , Α, Β, Γ, Δ, ,Θ , Λ, Ξ, ... ±, ... etc";

它适用于我尝试的大多数角色。

【讨论】:

【参考方案5】:

您使用了 ANSI 输出流。你需要使用

std::wcout << L"Blah blah blah some gibberish unicode: ĐĄßĞĝ\n";

另外,使用std::cin.get(),而不是system("PAUSE")

【讨论】:

感谢有关 cin.get() 的提示。我知道使用 system("PAUSE");是个坏习惯,但 Dev C++ 不支持我使用的其他任何东西。此外,开发 C++ 无法识别 wcout。我想我会遵循其他答案/cmets 中的建议并切换到 Visual Studio。我在使用该 IDE 时遇到的问题更少。 还应注意system("PAUSE") 不可移植,而cin.get() 可移植。

以上是关于在 Windows 中使用 C++ 将 Unicode 输出到控制台的主要内容,如果未能解决你的问题,请参考以下文章

c# string与c++ std::string的互相转换

在 Windows 中使用 C++ 将 Unicode 输出到控制台

如何在 Windows 10 上使用 C++ 将连续的原始音频数据记录到循环缓冲区中?

javascript Quontrol Key Identificador unico eventos绑定unico evento id控件jquery插件

使用 C++ 在 Windows 中获取 OSVersion

将 Python 嵌入到 C++ 应用程序中,无论是不是安装了 Python(在 Windows 上)