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

问题描述 投票:3回答:1

我正试图了解我所看到的某些行为。

我有这个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。

c++ powershell stdout cout setlocale
1个回答
0
投票

全部与编码有关。使用>重定向获取正确字符的原因是由于>重定向默认情况下使用UTF-16LE。因此,您设置的编码1252将自动转换为UTF-16。

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

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

我建议阅读有关此主题here的优秀mklement0的帖子。

根据评论编辑

取自cppreference

std :: setlocale在头文件<clocale>

中定义的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遵循外壳程序编码。

如果您具有Powershell 5.1及更高版本,则>Out-File的别名。您可以通过$PSDefaultParameterValues设置编码:

像这样:

$PSDefaultParameterValues['Out-File:Encoding'] = 'UTF8'

然后您将得到一个UTF-8文件(BOM可能很烦人!),而不是默认的UTF-16。

© www.soinside.com 2019 - 2024. All rights reserved.