为什么 ANSI 代码页和控制台代码页不同?

Why ANSI Code-Page and Console Code-Page are different?

Microsoft Windows 提供了几个查询当前代码页的函数:GetACP, GetConsoleOutputCP, GetConsoleCP.

他们return不同的价值观。例如,在我的机器上,GetACP returns 1252 而 GetConsoleOutputCPGetConsoleCP return 437.

(我们也可以在命令行运行 chcp得到437)

这个问题的背景是来自Visual Studio C++的错误信息:

error C2855: command-line option '/source-charset' inconsistent with precompiled header
error C2855: command-line option '/execution-charset' inconsistent with precompiled header

当预编译头文件使用与使用它们的 CPP 文件不同的默认代码页构建时(无论出于何种原因),会发生这些错误。
来自 MSDN docs:

If no byte-order mark is found, it assumes the source file is encoded using the current user code page, unless you specify a character set name or code page by using the /source-charset option.

所以我想弄清楚他们指的是哪个代码页,return由 GetACP 或其他人编写的代码页...

ANSI 和 OEM 代码页由系统启动时加载的系统区域设置决定。它们作为 PEB 字段 AnsiCodePageDataOemCodePageData 映射到每个进程中。 ntdll.dll 中的运行时库有许多函数可以处理这些字符串类型,例如 RtlAnsiStringToUnicodeStringRtlOemStringToUnicodeString.

Windows API 中以 A 结尾的函数是 ANSI,除了文件系统函数可以通过 SetFileApisToOEM 切换到 OEM。控制台 API 默认为 OEM 以与遗留应用程序兼容,并且可以通过 SetConsoleCPSetConsoleOutputCP 更改为另一个代码页。 chcp.com(或mode.com)调用这些函数,但它不允许将输入缓冲区和屏幕缓冲区设置为不同的代码页。

如果 ANSI 代码页是 1252,则 OEM 代码页不一定是 437。那只是在 U.S 中。语言环境。大多数使用 1252 作为 ANSI 代码页的西方语言环境将使用 850 作为 OEM 代码页。

声称使用用户代码页的应用程序可能不是指系统 ANSI 或 OEM 代码页。相反,它可能会调用 GetLocaleInfoEx 来查询 LOCALE_NAME_USER_DEFAULT 区域设置以获取 LOCALE_IDEFAULTANSICODEPAGELOCALE_IDEFAULTCODEPAGE.

由于遗留原因,命令控制台使用不同的代码页。控制台上的程序 运行 通常是为 DOS 编写的,字符集包括在这种情况下有用的线条图字符之类的东西。在具有本机 Windows 应用程序的图形环境中,扩展可用字符更为重要,因为线条将直接绘制而不是在字体中模拟。

默认代码页由 Windows 将使用的语言决定。不同的语言需要不同的字符,单个代码页不足以容纳欧洲语言使用的所有字符。例如,您会发现 code page 1250 在某些中欧和东欧地区使用。

How are these code pages determined per machine?

看看这个tableNational Language Support (NLS) API Reference

或查询您的注册表:

C:\>reg query HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage /v OEMCP

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage
    OEMCP    REG_SZ    850


C:\>reg query HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage /v ACP

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage
    ACP    REG_SZ    1252

Why does Windows provide different code pages for console and non-console?

由于与 MS-DOS 应用程序的向后兼容性,这些应用程序仍然可以 运行 在 16 位和 32 位 Windows 上,并且其中很多也被移植到 Windows安慰。此外,在 DOS 中使用 Alt code 的能力已经根深蒂固,如果用户不能再输入他们喜欢的特殊字符,他们会抱怨,所以 DOS 代码页是必须的

DOS 最初使用 code page 437 that was built into the EGA and VGA ROM. But later ISO and IEC came together to make new standard code pages, so Microsoft quickly jumped in and used code page 1252 for Windows, which was based on an early draft that later became ISO 8859-1

The source of this comes from the fact that the Windows code page 1252 was originally based on an ANSI draft, which became ISO Standard 8859-1

Why is the default 8-bit codepage called "ANSI"?

事实上,微软一直是早期采用者。比如它第一个采用了Korean standard and was the first to use Unicode,这两个都是后来的遗憾。前者从来没有被其他人使用过,而后者使得编写可移植代码变得困难,因为其他人都是后来的人并且使用更新更好的 UTF-8 代替

Microsoft 非常重视向后兼容性,因此在引入新的 Windows 代码页时,他们无法更改控制台应用程序的行为。因此他们只能对 GUI 应用程序进行更改。因此,遗留 Windows GUI 应用程序(在 Unicode 出现之前)将使用 ANSI 代码页,并且仍将为控制台应用程序维护一个单独的代码页。还需要介绍一种不同的输入特殊字符的方法:通过 Alt

之后的第一个小键盘键来区分
  • 如果是 数字键盘 1-9 则将使用 DOS 代码页 (A.K.A OEM code page)。 Alt+7 将生成代码点 7(U+2022 • 在 CP437 中)

  • 如果是 numpad 0 则将使用 Windows code page(A.K.A ANSI 代码页)。 Alt+0149 将生成代码点 149,与 CP1252

    中的 U+2022 • 相同
  • 如果是小键盘+那么输入就是十六进制的UCS2/UTF-16。这是使用 Unicode 的新 Windows GUI 应用程序的新行为。输入 Alt++2022 会得到相同的 U+2022 • 字符

    请注意,这需要通过在 HKCU\Control Panel\Input Method 注册表项中设置名称为 EnableHexNumpadREG_SZ 值来启用十六进制小键盘,然后重新启动

另见 Which character encoding is used for ALT-codes?


How are these code pages determined per machine?

每个语言环境都有 4 different default associated code pages:OEM (DOS)、ANSI (Windows)、EBCDIC 和 Mac(经典)代码页,现在只有前 2 个很重要.因此,在安装 Windows 后的默认美国语言环境中,您将分别拥有 DOS 和 Windows 代码页的 CP437 和 CP1252。但是这些可以很容易地更改,例如通过 chcp、API 调用或通过编辑注册表


What is the relation between code pages on the same machine? Is there a correlation between the console and non console code pages?

他们唯一的关系就是与语言环境的联系


Will machines with codepage 1252 always have console codepage of 437?

不,因为正如我所说,用户可以更改代码页。此外,可能 non-US 语言环境也使用 CP1252,但默认使用另一个 DOS 代码页