4

根据MSDN

“对于 Microsoft C/C++ 编译器,源字符集和执行字符集都是 ASCII。”

C++03

2.1 翻译阶段

"..任何不在基本源字符集 (2.2) 中的源文件字符都将替换为指定该字符的通用字符名。(实现可以使用任何内部编码,只要在源文件,以及在源文件中表示为通用字符名称的相同扩展字符(即使用 \uXXXX 表示法)等价地处理。)"

2.13.2 字符文字

“通用字符名称被转换为执行字符集中命名字符的编码。如果没有这样的编码,通用字符名称被转换为实现定义的编码。”

为了测试 MSVC++ 使用哪个执行字符集,我编写了以下代码:

wchar_t *str = L"中";
unsigned char *p = reinterpret_cast<unsigned char*>(str);
for (int i = 0; i < sizeof(L"中"); ++i)
{
   printf ("%x ", *(p + i));
}

输出显示2d 4e 0 0, 和0x4e2d是这个汉字的UTF-16 编码。所以我得出结论:UTF-16 被 MSVC 用作执行字符集(我的版本:2012 4.5.50709)

之后,我尝试将此字符打印到 Windows 控制台。由于控制台使用的默认语言环境是"C",因此我将语言环境设置为代码页 936,表示简体中文字符。

// use the execution environment locale setting, which is 936
wchar_t *str = L"中";
char* locale = setlocale(LC_ALL, "");
wprintf (L"%ls\n", str);

哪个输出:

我很好奇的是,以 UTF-16 编码的字符如何被区域设置(解码器)设置为非 UTF-16(MS 代码页 936)的 Windows 控制台解码?怎么会这样?

4

2 回答 2

1

以 UTF-16 编码的字符如何被语言环境(解码器)设置为非 UTF-16 的 Windows 控制台解码

有两种方法可以将文本写入控制台。使用 Win32 API 的字节方式WriteConsoleA为您提供使用控制台代码页(“ANSI”)解释的字节中的字符。Unicode 方式,WriteConsoleW接收一个 UTF-16LE 字符串并将字符直接写入控制台,而不必担心它使用的是什么代码页。

当输出是交互式控制台时printf使用stdio 函数。至少从 VS 2005 开始,WriteConsoleA该函数调用.wprintfWriteConsoleW

于 2013-05-03T12:59:20.163 回答
1

我想我明白了。

在 Microsoft C++ 2008(可能是 2005+)中,CRT 函数被实现为wprintf,它们在后台转换以 UTF-16 编码的宽字符串文字,以匹配当前的语言环境/代码页设置。所以这里发生的事情是在代码页 936 中转换为简体中文的字节。wcoutL"中"L"中"D6 D0

我错了setlocale设置控制台代码页。它只是设置 CRT 函数在“转换”期间使用的当前程序代码页。用于更改控制台代码页、命令chcp或 Win APISetConsoleOputputCP()实现。

由于我的控制台的默认页面是 936,因此该字符可以正确显示而没有问题。

于 2013-05-04T08:45:52.270 回答