gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 08:14:42 28 4
gpt4 key购买 nike

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

我有这个 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 对这些字节的误解)。

但是如果我将输出通过管道传输到文件,然后对文件进行cat,它看起来不错:

.\print_it.exe > out.txt
cat out.txt
日本語 # It displays fine, like this, if I redirect to a file and cat the file.

此外,无论我设置区域设置为何,Git bash 都会正确显示输出。

有人可以帮助我理解为什么 setlocale 会影响 Powershell 中输出的显示方式,即使相同的字节被写入 stdout 也是如此? Powershell 似乎能够以某种方式访问​​程序的区域设置并使用它来解释输出?

Powershell 版本为 5.1.17763.592。

最佳答案

这都是关于编码的。您使用 > 获得正确字符的原因重定向是由于 >重定向使用 UTF-16LE默认情况下。因此您设置的编码 1252 会自动转换为 UTF-16。

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

如果您使用Out-File-Encoding切换您可以更改目标文件的编码(同样取决于您的 PowerShell 版本)。

我建议阅读 mklement0 关于此主题的优秀文章 here .

根据评论进行编辑

取自 cppreference

std::setlocale C++ Localizations library Defined in header <clocale>

char* setlocale( int category, const char* locale);

The setlocale function installs the specified system locale or its portion as the new C locale. The modifications remain in effect and influences the execution of all locale-sensitive C library functions until the next call to setlocale. If locale is a null pointer, setlocale queries the current C locale without modifying it.

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

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

像这样:

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

然后你会得到一个 UTF-8 文件(带有 BOM,这可能很烦人!)而不是默认的 UTF-16LE。

编辑 - 根据OP的要求添加一些详细信息

PowerShell 使用 OEM 代码页,因此默认情况下您将获得在 Windows 上设置的内容。我建议阅读 encoding on windows 上的一篇优秀文章。关键是,如果没有对 powershell 进行 UTF8 设置,您将处于现有的代码页上。

output.exe正在将语言环境设置为 English_United States.1252在 c++ 程序中和 output_original.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)给出输出。请注意,在两个版本中,十六进制转储是相同的,但输出(带编码)不同。

如果您使用 [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将使用该语言环境 (1252) 进行格式化,然后将这些字符转换为 UTF8 格式(这就是第一个和第二个示例略有不同的原因)。当您不在 C++ 应用程序中强制使用区域设置时,将采用 PowerShell 编码(现在为 UTF8),您将获得正确的输出。

我发现有趣的一件事是,如果你将 Windows 系统区域设置更改为中文兼容的区域设置(中国、澳门、柴湾、香港等),那么在不强制使用 UTF8 时,你会得到一些中文字符,但会得到不同的字符。这意味着这些字节只是 Unicode,因此只有在那里它才起作用。如果您在 PowerShell 中强制使用 UTF8,即使使用中文 Windows 系统区域设置,它也可以正常工作。

我希望这能更大程度地回答您的问题。

咆哮:我花了很长时间才调查,因为 VS 2019 社区版已经过期(WFT MS?),而且我无法注册它,因为注册窗口完全是空白的。谢谢女士,但不用了。

关于c++ - 为什么 LC_ALL setlocale 设置会影响 Powershell 中的 cout 输出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58883361/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com