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

Why does wprintf transliterate Russian text in Unicode into Latin on Linux?

为什么会出现下面的程序

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

int main() {
  wprintf(L"Привет, мир!");
}

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

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

非宽版 printf("Привет, мир!") 按预期打印此文本(“Привет, мир!”)。

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

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

setlocale(LC_ALL, "ru_RU.utf8"); // Russian Unicode
setlocale(LC_ALL, "en_US.utf8"); // English US Unicode

或当前系统语言环境(这可能是您需要的):

setlocale(LC_ALL, "");

完整的程序将是:

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

int main() {
  setlocale(LC_ALL, "ru_RU.utf8");
  wprintf(L"Привет, мир!\n");
}

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

why does it transliterate Russian text in Unicode into Latin as opposed to transcoding it into UTF-8 or using replacement characters?

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

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

注意:(在我知道的实现中)确定 FILE 流的编码并 在当时保存 流方向(宽与正常)是选择。请记住在 对 stdout 做任何事情之前设置语言环境 (即 this vs this)。