【问题标题】:Why ANSI Code-Page and Console Code-Page are different?为什么 ANSI 代码页和控制台代码页不同?
【发布时间】:2017-08-28 14:09:39
【问题描述】:

Microsoft Windows 提供了几个查询当前代码页的函数: GetACPGetConsoleOutputCPGetConsoleCP

它们返回不同的值。例如,在我的机器上,GetACP 返回 1252,而 GetConsoleOutputCPGetConsoleCP 返回 437。

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

  • 为什么 Windows 为控制台和非控制台提供不同的代码页?
  • 如何确定每台机器的这些代码页?
  • 同一台机器上的代码页之间有什么关系?控制台和非控制台代码页之间是否存在关联?代码页为 1252 的机器是否总是控制台代码页为 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

如果未找到字节顺序标记,则假定源文件已编码 使用当前用户代码页,除非您指定字符集 使用 /source-charset 选项的名称或代码页。

所以我试图找出它们引用的代码页,GetACP 或其他返回的代码页...

【问题讨论】:

    标签: windows visual-studio visual-studio-2015 windows-console codepages


    【解决方案1】:

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

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

    如果 ANSI 代码页是 1252,则 OEM 代码页不一定是 437。这仅适用于美国区域设置。大多数使用 1252 作为 ANSI 代码页的西方语言环境将使用 850 作为 OEM 代码页。

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

    【讨论】:

    • 对于投反对票的人,如果你在没有解释的情况下投反对票,那是你的特权。但至少提供一点反馈让我知道哪里出了问题会更有帮助;如果我有办法改进答案,或者你的理由足够重要,我应该删除这个答案。
    • 投反对票的人可能是在拖钓。这个问题也被否决了,没有解释。现在你提到的最后一件事让我感到困惑。除了 ANSI 和 OEM,我们还有其他代码页吗?根据this MSDN pageLOCALE_IDEFAULTANSICODEPAGE返回ANSI代码页,LOCALE_IDEFAULTCODEPAGE返回OEM代码页。在什么情况下它们与GetACPGetConsoleCP 等返回的代码页不同?
    • 正如我提到的,系统区域设置是 Windows ANSI API 中带有“A”后缀的函数所使用的。它通常使用系统 ANSI 代码页,但文件系统 API 可以切换到系统 OEM 代码页,并且控制台默认为 OEM。 ANSI API 已弃用。程序应该使用以“W”为后缀的 Unicode API,而像 GetLocaleInfoEx 这样的许多新函数甚至都没有 ANSI 实现。
    • 最好将文本保存为带有 BOM 的 UTF-8 或 UTF-16,而不是使用旧代码页。但我们并没有脱离过去,代码页在许多情况下仍然是相关的。
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      这些代码页是如何确定每台机器的?

      看看这张表National 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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-03-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-30
        • 2021-07-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多