C++ 为什么LC_ALL setlocale设置会影响Powershell中的cout输出?

C++ 为什么LC_ALL setlocale设置会影响Powershell中的cout输出?,c++,powershell,stdout,cout,setlocale,C++,Powershell,Stdout,Cout,Setlocale,我试图理解我看到的一些行为 我有这个C++程序: //Outputter.cpp:定义控制台应用程序的入口点。 // #包括“stdafx.h” #包括 int main() { //UTF-8字节用于“日本語" std::cout这一切都是关于编码的。使用重定向获得正确字符的原因是重定向默认使用。因此,您设置的编码1252会自动转换为UTF-16 根据您的PowerShell版本,您可以更改或不能更改重定向的编码 如果将Out File与-Encoding开关一起使用,则可以更改目标文件的编码

我试图理解我看到的一些行为

我有这个C++程序:

//Outputter.cpp:定义控制台应用程序的入口点。
//
#包括“stdafx.h”
#包括
int main()
{
//UTF-8字节用于“日本語"

std::cout这一切都是关于编码的。使用
重定向获得正确字符的原因是
重定向默认使用。因此,您设置的编码1252会自动转换为UTF-16

根据您的PowerShell版本,您可以更改或不能更改重定向的编码

如果将
Out File
-Encoding
开关一起使用,则可以更改目标文件的编码(同样取决于您的PowerShell版本)

我建议阅读关于这个主题的非常优秀的mklement0文章

根据评论进行编辑 取自

std::setlocale 在标题<代码> <代码>

中定义的C++本地化库
char*setlocale(int-category,const-char*locale);

setlocale函数将指定的系统语言环境或其部分安装为新的C语言环境。修改仍然有效并影响 执行所有对区域设置敏感的C库函数,直到下一个 调用setlocale。如果locale是空指针,则setlocale查询 当前C语言环境,而不修改它

发送到
std::cout
的字节相同,但
std::cout
是一个区域设置敏感函数,因此它优先于PowerShell UTF-8设置。如果省略
setlocale()
函数,则
std::cout
遵循shell编码

如果您有Powershell 5.1及以上版本,则
输出文件的别名。您可以通过
$PSDefaultParameterValues
设置编码:

像这样:

$PSDefaultParameterValues['Out-File:Encoding'] = 'UTF8'
然后,您将得到一个UTF-8文件(带有BOM表,这可能很烦人!),而不是默认的UTF-16LE

编辑-根据OP的要求添加一些详细信息 PowerShell正在使用OEM代码页,因此默认情况下,您将获得在windows上设置的内容。我建议您在上阅读一篇精彩的文章。重点是,如果没有对PowerShell进行UTF8设置,您将处于您的代码页上

< > >代码>输出.exe < /> >将区域设置为<代码>英语>美国。1252代码> C++ >代码> > OutPuxEng原原件.exe <代码>没有做任何更改:

以下是不带UTF8 PowerShell设置的输出:

c:\t>.\output.exe
æ-¥æo¬èªz  --> nonsese within the win1252 code page
c:\t>.\output.exe | hexdump
0000000 97e6 e6a5 ac9c aae8 009e --> both hex outputs are the same!
0000009
c:\t>.\output_original.exe
日本語  --> nonsense but different one! (depens on your locale setup - my was English)
c:\t>.\output_original.exe | hexdump
0000000 97e6 e6a5 ac9c aae8 009e  --> both hex outputs are the same!
0000009
那么这里会发生什么呢?您的程序会根据程序本身或windows中设置的区域设置(在我的虚拟机上是OEM代码1252)发出输出。请注意,在这两个版本中,hextump是相同的,但不是输出(带编码)

如果使用
[System.Text.Encoding]:UTF8将PowerShell设置为UTF8

PS C:\t> [System.Console]::OutputEncoding = [System.Console]::InputEncoding = [System.Text.Encoding]::UTF8
PS C:\t> .\output.exe 
日本語  --> the english locales 1252 set within program notice that the output is similar to the above one (but the hexdump is different)
PS C:\t> .\output.exe | hexdump
0000000 bbef 3fbf 3f3f 0a0d  -> again hex dump is same for both so they are producing the same output!
0000008
PS C:\t> .\output_original.exe
日本語 --> correct output due to the fact you have forced the PowerShell encoding to UTF8, thus removing the output dependence on the OEM code (windows)
PS C:\t> .\output_original.exe | hexdump
0000000 bbef 3fbf 3f3f 0a0d -> again hex dump is same for both so they are producing the same output!
0000008

这里发生了什么?如果你在C++应用程序强制了区域设置,那么<代码> STD:cOUT/CODE>将用该区域设置格式(1252),然后将这些字符转换成UTF8格式(这就是为什么第一个和第二个示例有点不同的原因)。当您不强制在C++应用程序中使用区域设置时,则使用PuxSeCK编码,现在是UTF8,并且得到正确的输出。 我发现有趣的一点是,如果您将windows系统区域设置更改为与中文兼容的区域设置(中国、澳门、台湾、香港等)当不强制使用UTF8时,您会得到一些中文字符,但会得到不同的字符。这意味着这些字节仅为Unicode,因此只有在那里才有效。如果您在PowerShell上强制使用UTF8,即使在中文windows系统区域设置下也能正常工作

我希望这能在更大程度上回答你的问题

咆哮:
我花了很长时间进行调查,因为VS2019社区版已经过期(WFT MS?)我不能注册它,因为登记窗口是完全空白的。谢谢,但是不谢谢。< /P>我对Windows一无所知,但是另一种可能是C++运行时检测它正在输出到终端并改变活动代码页的持续时间。你使用的是什么版本?@图卡,我想是V5.1.17763.592I。我理解为什么输出到一个文件,然后对该文件进行catting操作,或者至少我不觉得这很神秘(实际上我输出的是UTF-8,这是自动转换的,不是1252)但是我不明白为什么写在STOUT上的字节被C++代码中的区域设置所不同的地方。@ Aurast你正在向UTF-8输出<代码> [Stuto.Text .Cord]::UTF8<代码>,但是正如我在回答中所说的<代码> >代码>将它转换成UTF-16(即使是UTF8的基础)。我明白了,所以你对
setlocale()
的效果感到惊讶。我将编辑我的答案。我将把这个标记为答案,但我希望得到更多的细节。如果你知道更多,如果你能更新,我将不胜感激。例如:该程序到底给控制台提供了什么,根据区域设置的不同?它会说“嘿,控制台,这里有一些字节,顺便说一下,我的语言环境设置为1252"但是,我还不确定在幕后会发生什么,导致不同shell之间的行为差异。@ AurStand我将添加这些细节,但是我需要尽可能地接近你的Env。你使用C++编译器的编译器是什么?@ Aurast,你使用的是代码> STD。afx.h
我打赌你正在使用VS。我会对此发表评论。
c:\t>.\output.exe
æ-¥æo¬èªz  --> nonsese within the win1252 code page
c:\t>.\output.exe | hexdump
0000000 97e6 e6a5 ac9c aae8 009e --> both hex outputs are the same!
0000009
c:\t>.\output_original.exe
日本語  --> nonsense but different one! (depens on your locale setup - my was English)
c:\t>.\output_original.exe | hexdump
0000000 97e6 e6a5 ac9c aae8 009e  --> both hex outputs are the same!
0000009
PS C:\t> [System.Console]::OutputEncoding = [System.Console]::InputEncoding = [System.Text.Encoding]::UTF8
PS C:\t> .\output.exe 
日本語  --> the english locales 1252 set within program notice that the output is similar to the above one (but the hexdump is different)
PS C:\t> .\output.exe | hexdump
0000000 bbef 3fbf 3f3f 0a0d  -> again hex dump is same for both so they are producing the same output!
0000008
PS C:\t> .\output_original.exe
日本語 --> correct output due to the fact you have forced the PowerShell encoding to UTF8, thus removing the output dependence on the OEM code (windows)
PS C:\t> .\output_original.exe | hexdump
0000000 bbef 3fbf 3f3f 0a0d -> again hex dump is same for both so they are producing the same output!
0000008