Windows 为什么通过|%{echo";$";}管道传输我的命令会使UTF-8工作?

Windows 为什么通过|%{echo";$";}管道传输我的命令会使UTF-8工作?,windows,powershell,unicode,utf-8,Windows,Powershell,Unicode,Utf 8,在Windows PowerShell中,我使用了chcp 65001,并选择了一种包含我想要的所有字符的字体 如果我用type file.u8显示一个UTF-8文件,它工作正常,我得到了所需的字符 如果我运行myprogram.exe,则在第一个非ASCII字符之后没有输出(如果在chcp 65001之前运行,则生成mojibake) 如果我运行myprogram.exe>test.u8,然后运行type test.u8,则有效,并获得所需的输出 因此,我推断我可以使用myprogram.ex

在Windows PowerShell中,我使用了
chcp 65001
,并选择了一种包含我想要的所有字符的字体

如果我用
type file.u8显示一个UTF-8文件,它工作正常,我得到了所需的字符

如果我运行
myprogram.exe
,则在第一个非ASCII字符之后没有输出(如果在
chcp 65001
之前运行,则生成mojibake)

如果我运行
myprogram.exe>test.u8
,然后运行
type test.u8
,则有效,并获得所需的输出

因此,我推断我可以使用
myprogram.exe |%{echo“$\u”}
绕过该文件(使用我有限的PowerShell知识!),而有效。所以,当C++运行时直接与一个正在破坏UTF-8输出的控制台对话时,它看起来是很特别的。
(如果我使用宽字符,我可以得到所需的输出,但实际上我最终不想要UTF-16输出,我想要UTF-8。我只想要打印调试信息的方便性,而不需要额外的字符转换)

在与@eryksun的评论交流中,我意识到我忽略了一个实验:我所有使用宽字符的尝试都是成功的。那么,如果
type
echo
实际上能够读取UTF-8并输出宽字符呢?所以我重定向到一个文件:

myprogram.exe | % {echo "$_"} > test.txt
现在检查文本文件,它被Notepad++检测为“UCS-2 LE BOM”。事实上,所有有效的案例(
类型
,所有重定向到文件等)都产生了多字节字符。甚至
type foo.u8>foo.txt
也显示了预期的大小增加


因此,真正的问题不是我的程序(它正在成功输出UTF-8),而是有几种东西能够无声地将其转换为Windows喜欢的东西。

通过
SetConsoleOutputCP
(或命令行中的chcp.com)设置65001的输出代码页在Windows 8和10中工作。它在旧版本中是有缺陷的。即使在Windows 10中,通过
setConsoleECP
(或通过chcp.com)将输入代码页设置为65001也仅限于7位ASCII文本,因为conhost.exe中的设计不好,无法处理可变大小的编码。然而,这并不能解释为什么没有输出。如果没有重定向,这应该与PowerShell无关;myprogram.exe直接写入控制台。提供一个简单的示例,让人们可以使用它。另外,我不了解您使用的关于UTF-8的
setlocale
。在最新版本的Windows 10中,CRT仅支持UTF-8作为区域设置编码。另一方面,低I/O层(即
\u wopen
\u setmode
)支持
\u U8TEXT
模式,UTF-8在写入非控制台文件时对宽字符串进行编码,但是对控制台I/O使用宽字符API。@eryksun我使用了
SetConsoleOutputCP
,其效果与在控制台中键入
chcp
相同。我认为最小的复制值是
printf(u8“你好\n“
.chcp.com只需调用
SetConsoleCP
setconsoleoutcp
。输入和输出代码页在conhost.exe中是全局的,而不是每个应用程序,因此无论您是直接调用函数还是运行
chcp.com 65001
。在这种情况下,您是否将CRT区域设置保留为默认的“C”模式?@eryksun我将其保留,并尝试将其设置为
“chinese”
“chinese simplified”
,并验证是否返回了有效的区域设置。我的结论是,这种建议与宽字符输出相关,但无法使UTF-8输出正常工作。当myprogram.exe将UTF-8写入管道时,PowerShell会将其转换为本机UTF-16字符串。它使用宽字符API写入控制台。当您需要程序之间的直接二进制管道时,PowerShell尤其令人讨厌。它将自己设置为中间人,转换文本编码和CRLF行结尾。我认为在这种情况下最简单的选择是使用
cmd/c
。我建议阅读两个评论链接。它应该能让您深入了解powershell和编码。