【问题标题】:How does convertion between char and wchar_t work in Windows?char 和 wchar_t 之间的转换如何在 Windows 中工作?
【发布时间】:2015-12-04 11:17:12
【问题描述】:

在 Windows 中,有像 mbstowcs 这样的函数可以在 char 和 wchar_t 之间进行转换。还有from_bytes<std::codecvt<wchar_t, char, std::mbstate_t>>等C++函数可以使用。

但是在 char 和 wchar_t 显然大小不同的情况下,这如何工作?我假设系统代码页以某种方式涉及?但是如果 wchar_t 不能与 char 相关联会发生什么(它毕竟可以包含更多的值)?

如果必须使用 char 的代码(可能是由于库)在具有不同代码页的计算机之间移动,会发生什么情况?假设它只使用在 ASCII 范围内的数字(0-9),那总是安全的吗?

最后,在本地语言不能用 256 个字符表示的计算机上会发生什么?在这种情况下,char 的概念似乎与存储(例如 utf8)完全无关。

【问题讨论】:

  • But what happens if a wchar_t can't be correlated to a char (it can after all contain a lot more values)? 这正是需要担心的事情。真正的答案是“不要转换为字符”。如果您有 wchar_t / UTF16 数据并且不想丢失内容,请保持原样。 (当然还有其他编码可以无损转换,但通常默认的一字节编码不在其中)
  • Microsoft 的mbstowcs 的最后一个参数是locale,它控制如何执行转换。 Standard one 使用 setlocale。这些都是病态的。任何强大的应用程序中的国际化都应由专用 (Unicode) 库(icu、Qt、boost、...)处理
  • 关于另外两个问题,同样,不要将 unicode 编码下转换为某种 256 值编码。
  • 请注意,仅仅因为 Windows API 假定 chars 位于系统代码页中,这并不意味着 chars 始终存在。例如,某些库可能会假设它们是 UTF-8,并且可以从 wchar_t(在 Windows 上为 UTF-16)转换为 UTF-8。
  • @Drop:icu Qt 和 boost 将归结为标准函数,否则它们本身不会“健壮”。它们是用于定义标准必须是什么的标准前实现,并且也将通过标准实现

标签: c++ windows character-encoding


【解决方案1】:

这完全取决于所使用的 cvt 方面,如 here

所述

在您的情况下,(std::codecvt<wchar_t, char, std::mbstate_t>) 这一切都归结为使用全局语言环境的mbsrtowcs / wcsrtombs。 (即“C”语言环境,如果您不将其替换为系统语言环境)

【讨论】:

  • 很有趣,所以基本上只要您不手动更改全局语言环境,它将是 C 语言环境,并且代码可以在任何计算机上运行。不过,如果我有一个未在 C 语言环境中映射的 wchar_t 会发生什么?
  • 在这种情况下,规范没有帮助。该函数可能会失败(规范说明如何)或者可能会尝试近似。一般来说 - 如果需要国际化 - 最好在程序内部使用 UTF8 并在调用 WIN-API 时执行 UTF8-to-16。 C 语言环境适用于基于英语的编程语言。但仅此而已。 UTF8 语言环境被广泛接受,以至于其他一切都将很快消失(请注意,UTF8 与前 127 个字符中的 ASCII 相同,与 C 语言环境中的相同,因此正式程序保持不变)。
【解决方案2】:

我不知道mbstowcs(),但我认为它类似于std::codecvt<cT, bT, std::mbstate_t>。后者以两种类型旅行:

  • 一个字符类型cT,在你的代码wchar_t中。
  • 一个字节类型bT,通常是char

第三种类型,std::mbstate_t,用于存储调用std::codecvt<...> facet 之间的任何中间状态。刻面不能有任何可变状态,调用之间的任何状态都需要以某种方式获得。遗憾的是,std::mbstate_t 的结构未指定,即在创建自己的代码转换方面时没有可移植的方式来实际使用它。

std::codecvt<...> 的每个实例都实现了外部编码(例如 UTF8)的字节与字符之间的转换。最初,每个字符都应该是一个独立的实体,但各种原因(主要来自 C++ 社区之外,尤其是对 Unicode 所做的更改)导致内部字符本身实际上是一种编码。通常使用的内部编码是 UTF8 代表 char 和 UTF16 或 UCS4 代表 wchar_t(取决于 wchar_t 是使用 16 位还是 32 位)。

std::codecvt<...> 完成的解码转换将外部编码中的传入字节转换为内部编码的字符。例如,当外部编码为 UTF8 时,传入的字节被转换为 32 位代码点,然后通过在必要时将它们拆分为 wchar_t(例如,当 wchar_t 为 16 位时)将其固定为 UTF16 字符。

此过程的详细信息未指定,但会涉及一些位屏蔽和移位。此外,不同的转换将使用不同的方法。如果外部和内部编码之间的映射不像将一种 Unicode 表示映射到另一种表示那样简单,则可能有合适的表提供实际映射。

【讨论】:

    【解决方案3】:

    什么是 in char 数组 is 实际上是一个 UTF-8 编码的字符串,然后您可以使用

    #include <locale>
    #include <codecvt>
    #include <string>
    
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
    std::string narrow = converter.to_bytes(wide_utf16_source_string);
    std::wstring wide = converter.from_bytes(narrow_utf8_source_string);
    

    https://stackoverflow.com/a/18597384/6345 中更详细的描述

    【讨论】:

      猜你喜欢
      • 2012-06-30
      • 2014-07-03
      • 1970-01-01
      • 2017-03-03
      • 2018-01-07
      • 2011-03-14
      • 2021-01-29
      • 2010-12-24
      相关资源
      最近更新 更多