如何在Windows控制台上输出Unicode字符串

Phi*_*ipp 12 windows unicode console

关于这个问题已经有一些问题了.我认为我的问题有点不同,因为我没有实际问题,我只是在考虑学术兴趣.我知道Windows的UTF-16实现有时与Unicode标准(例如整理)相矛盾,或者更接近旧UCS-2而不是UTF-16,但我会在这里保留"UTF-16"术语,原因是简单.

背景:在Windows中,一切都是UTF-16.无论你是在处理内核,图形子系统,文件系统还是其他什么,你都要传递UTF-16字符串.Unix意义上没有语言环境或字符集.为了与中世纪版本的Windows兼容,有一个名为"codepages"的东西已经过时但仍然受到支持.AFAIK,只有一个正确且非过时的函数可以将字符串写入控制台,即WriteConsoleW采用UTF-16字符串.此外,类似的讨论也适用于输入流,我也会忽略它.

但是,我认为这代表了Windows API中的一个设计缺陷:有一个通用函数可以用来写入所有被调用的流对象(文件,管道,控制台......)WriteFile,但是这个函数是面向字节的,不是接受UTF-16字符串.文档建议使用WriteConsoleW控制台输出,这是面向文本的,和WriteFile对于其他一切,这是面向字节的.由于控制台流和文件对象都由内核对象句柄表示,并且控制台流可以重定向,因此必须为标准输出流的每次写入调用一个函数,以检查句柄是表示控制台流还是文件,从而破坏多态性.OTOH,我认为Windows在文本字符串和原始字节之间的分离(在许多其他系统中镜像,如Java或Python)在概念上优于Unix的char*方法,忽略编码并且不区分字符串和字节数组.

所以我的问题是:在这种情况下该怎么办?为什么即使在微软自己的库中也没有解决这个问题?.NET Framework和C和C++库似乎都遵循过时的代码页模型.您将如何设计Windows API或应用程序框架来规避此问题?

我认为一般问题(不容易解决)是所有库都假设所有流都是面向字节的,并在此基础上实现面向文本的流.但是,我们看到Windows在操作系统级别上确实有特殊的面向文本的流,并且库无法处理这个问题.因此,无论如何,我们必须对所有标准库进行重大更改.一种快速而肮脏的方法是将控制台视为一种特殊的面向字节的流,只接受一种编码.这仍然要求必须绕过C和C++标准库,因为它们没有实现WriteFile/ WriteConsoleWswitch.那是对的吗?

Alb*_*ert 5

我/我们在大多数(跨平台)应用程序/项目中使用的一般策略是:我们只是在任何地方使用UTF-8(我的意思是真正的标准).我们使用std :: string作为容器,我们只是将所有内容解释为UTF8.我们也以这种方式处理所有文件IO,即我们期望UTF8并保存UTF8.在我们从某个地方获取字符串并且我们知道它不是UTF8的情况下,我们将其转换为UTF8.

我们偶然发现WinUTF16的最常见情况是文件名.因此,对于每个文件名处理,我们将始终将UTF8字符串转换为WinUTF16.如果我们在目录中搜索文件,那么另一种方式.

控制台并未真正用于我们的Windows版本(在Windows版本中,所有控制台输出都包含在文件中).由于我们到处都有UTF8,我们的控制台输出也是UTF8,适用于大多数现代系统.此外,Windows控制台日志文件的内容为UTF8,Windows上的大多数文本编辑器都可以正常读取.

如果我们更多地使用WinConsole,如果我们非常关心所有特殊字符都正确显示,我们可能会编写一些自动管道处理程序,我们安装在它们之间fileno=0,stdout并且将WriteConsoleW按照你的建议使用真实的(如果有的话)没有更简单的方法).

如果你想知道如何实现这样的自动管道处理程序:我们已经为所有类似POSIX的系统实现了这样的功能.代码可能不适用于Windows,但我认为应该可以移植它.我们当前的管道处理器类似于什么tee.即如果你这样做cout << "Hello" << endl,它将被打印stdout在一些日志文件中.如果您对此操作感兴趣,请查看代码.