在 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()->in_avail()
,2-numeric_limits<streamsize>::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.h
和io.h
(如this answer 中所述,并在this blog post 中记录)。
【讨论】:
这并没有解决控制台通常处于 ANSI 或 OEM 模式这一事实。 这基本上是对的,但是...cmd
默认情况下会处理 Unicode 输出到控制台,但在重定向到文件时不会。使用/u
也可以将Unicode 输出到重定向文件。在这两种情况下,“Unicode”都意味着UTF-16
,就像在 Windows 上一样。 chcp 65001
将ANSI
代码页设置为UTF-8
,这与宽字符、wcout
和cmd /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 不会进行转码。转码仅在写入控制台时发生,与呈现文本所需的时间相比可以忽略不计。当输出被重定向时,没有转码,这是fmt
与wcout
相比的另一个优势。
@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插件