为什么 wprintf 在 Linux 上将 Unicode 中的俄语文本音译为拉丁语?

vit*_*aut 35 c linux printf wchar non-ascii-characters

为什么下面的程序

#include <stdio.h>
#include <wchar.h>

int main() {
  wprintf(L"??????, ???!");
}
Run Code Online (Sandbox Code Playgroud)

打印“女贞,先生!” 在 Linux 上?具体来说,为什么它将 Unicode 中的俄语文本音译为拉丁语,而不是将其转码为 UTF-8 或使用替换字符?

在 Godbolt 上演示此行为:https ://godbolt.org/z/36zEcG

非宽版会printf("??????, ???!")按预期打印此文本(“??????, ???!”)。

Sta*_*irl 31

因为宽字符的转换是根据当前设置的语言环境完成的。默认情况下,C 程序始终以仅支持 ASCII 字符的“C”语言环境开始。

您必须先切换到任何俄语或 UTF-8 语言环境:

setlocale(LC_ALL, "ru_RU.utf8"); // Russian Unicode
setlocale(LC_ALL, "en_US.utf8"); // English US Unicode
Run Code Online (Sandbox Code Playgroud)

或者到当前系统区域设置(这可能是您需要的):

setlocale(LC_ALL, "");
Run Code Online (Sandbox Code Playgroud)

完整的程序将是:

#include <stdio.h>
#include <wchar.h>
#include <locale.h>

int main() {
  setlocale(LC_ALL, "ru_RU.utf8");
  wprintf(L"??????, ???!\n");
}
Run Code Online (Sandbox Code Playgroud)

至于您的代码在其他机器上按原样运行 - 这是由于 libc 在那里运行的方式。某些实现(如 musl)不支持非 Unicode 语言环境,因此可以无条件地将宽字符转换为 UTF-8 序列。

  • @Jabberwocky 您的计算机上安装了“ru_RU.utf8”语言环境吗?如果没有,那么设置就会失败。使用 `""` (默认语言环境),这可能是 UTF-8 语言。任何 unicode 语言环境都可以。 (6认同)
  • @Jabberwocky 那么你使用什么语言环境?如果您在美国,请尝试“en_US.utf8”。 (3认同)
  • 当我在带有或不带有“setlocale(LC_ALL, "ru_RU.utf8")”或“setlocale(LC_ALL, "")”的Godbolt上运行它时,它会逐字打印“Privet,mir!”。 (2认同)
  • 但为什么要音译呢?它记录在某处吗? (2认同)

Kam*_*Cuk 10

为什么它将 Unicode 中的俄语文本音译为拉丁语,而不是将其转码为 UTF-8 或使用替换字符?

因为程序的起始语言环境是默认的C语言环境。所以它将宽字符串翻译成C语言环境。C语言环境不处理 UTF-8 或任何 unicode,因此您的标准库最好将宽字符转换为C语言环境中使用的一些基本字符集。

您可以将语言环境更改为任何UTF-8 语言环境,并且程序应该输出 UTF-8 字符串。

注意:(在我知道的实现中)FILE流的编码是选择流方向(宽与正常)确定并保存的。请记住执行任何操作之前设置语言环境stdout(即thisthis)。