我正试图了解我所看到的某些行为。
我有这个C ++程序:
// Outputter.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
int main()
{
// UTF-8 bytes for "日本語"
std::cout << (char)0xE6 << (char)0x97 << (char)0xA5 << (char)0xE6 << (char)0x9C << (char)0xAC << (char)0xE8 << (char)0xAA << (char)0x9E;
return 0;
}
如果我在Powershell中运行以下命令:
[System.Console]::OutputEncoding = [System.Console]::InputEncoding = [System.Text.Encoding]::UTF8
.\print_it.exe # This is the above program ^
日本語 # This is the output as displayed in Powershell
然后将日本語
打印并正确显示在Powershell中。
但是,如果我在代码中添加setlocale(LC_ALL, "English_United States.1252");
,如下所示:
int main()
{
setlocale(LC_ALL, "English_United States.1252");
// UTF-8 bytes for "日本語"
std::cout << (char)0xE6 << (char)0x97 << (char)0xA5 << (char)0xE6 << (char)0x9C << (char)0xAC << (char)0xE8 << (char)0xAA << (char)0x9E;
return 0;
}
程序现在将垃圾信息输出到Powershell(确切地说是日本語
,这是代码页1252对那些字节的错误解释。
但是如果我将输出通过管道传输到文件中,然后将其分类为文件,则看起来不错:
.\print_it.exe > out.txt
cat out.txt
日本語 # It displays fine, like this, if I redirect to a file and cat the file.
此外,无论我setlocale
做什么,Git bash都能正确显示输出。
有人可以帮助我理解为什么即使将相同的字节写入stdout,setlocale仍会影响Powershell中输出的显示方式吗?看来Powershell能够以某种方式访问程序的语言环境,并使用它来解释输出?
Powershell版本是5.1.17763.592。
全部与编码有关。使用>
重定向获取正确字符的原因是由于>
重定向默认情况下使用UTF-16LE。因此,您设置的编码1252将自动转换为UTF-16。
根据您的PowerShell版本,您可以或不能更改重定向的编码。
如果将Out-File
与-Encoding
开关一起使用,则可以更改目标文件的编码(同样取决于PowerShell版本)。>>
我建议阅读有关此主题here的优秀mklement0的帖子。
std :: setlocale在头文件
中定义的C ++本地化库<clocale>
char* setlocale( int category, const char* locale);
setlocale函数将指定的系统语言环境或其部分安装为新的C语言环境。修改仍然有效并影响执行所有对语言环境敏感的C库函数,直到下一个调用setlocale。如果locale是空指针,则setlocale查询当前的C语言环境而无需对其进行修改。
您要发送到
std::cout
的字节是相同的,但是std::cout
是对语言环境敏感的函数,因此它会覆盖PowerShell UTF-8设置。如果省略setlocale()
功能,则std::cout
遵循外壳程序编码。
如果您具有Powershell 5.1及更高版本,则>
是Out-File
的别名。您可以通过$PSDefaultParameterValues
设置编码:
像这样:
$PSDefaultParameterValues['Out-File:Encoding'] = 'UTF8'
然后您将得到一个UTF-8文件(BOM可能很烦人!),而不是默认的UTF-16。