char vs wchar_t 何时使用哪种数据类型

新手上路,请多包涵

我想了解 charwchar_t 之间的区别?我知道 wchar_t 使用更多字节,但我可以得到一个明确的例子来区分我何时使用 charwchar_t

原文由 Ankit Goel 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 722
2 个回答

从根本上说,当编码的符号多于 char 可以包含的符号时,使用 wchar_t

背景

char 类型有足够的容量容纳 ASCII 字符集中的任何字符(编码)。

问题是许多语言需要比 ASCII 更多的编码。因此,需要更多而不是 127 种可能的编码。有些语言有超过 256 种可能的编码。 char 类型不保证范围大于 256。因此需要新的数据类型。

wchar_t 又名宽字符,为编码提供了更多空间。

概括

当编码范围为 256 或更少时使用 char 数据类型,例如 ASCII。当您需要超过 256 的容量时,请使用 wchar_t

首选 Unicode 来处理大型字符集(例如表情符号)。

原文由 Thomas Matthews 发布,翻译遵循 CC BY-SA 3.0 许可协议

简短回答:

你不应该在现代 C++ 中使用 wchar_t ,除非与特定于操作系统的 API 交互(基本上使用 wchar_t 仅调用 Windows API 函数)。

长答案:

标准 C++ 库的设计意味着只有一种处理 Unicode 的方法——将 UTF-8 编码的字符串存储在 char 数组中,因为几乎所有函数都只存在于 char 变体中(想想 std::exception::what )。

在 C++ 程序中,您有两个语言环境:

  • std::setlocale
  • std::locale::global

不幸的是,它们都没有定义打开文件的标准函数的行为(如 std::fopenstd::fstream::open 等)。操作系统之间的行为不同:

  • Linux 编码不可知,因此这些函数只需将 char 字符串传递给底层系统调用
  • 在 Windows 上,在进行系统调用之前,使用用户特定的语言环境将字符字符串转换为宽字符串

在 Linux 上一切正常,因为每个人都使用基于 UTF-8 的语言环境,因此所有传递给 main 函数的用户输入和参数都将采用 UTF-8 编码。但是您可能仍需要将当前语言环境显式切换为 UTF-8 变体,因为默认情况下 C++ 程序开始使用默认 "C" 语言环境。此时,如果您只关心 Linux 而不需要支持 Windows,则可以使用 char 数组和 std::string 假设它是 UTF-8 序列并且一切都“正常工作”。

当您想要支持 Windows 时会出现问题,因为您总是有额外的第三种语言环境:为当前用户设置的一种,可以在“控制面板”中的某处进行配置。主要问题是该语言环境从来都不是 Unicode 语言环境,因此 不可能 使用 std::fopen(const char *)std::fstream::open(const char *) 之类的函数来使用 Unicode 路径打开文件。在 Windows 上,您必须使用使用非标准 Windows 特定功能的自定义包装器,例如 _wfopenstd::fstream::open(const wchar_t *) 在 Windows 上。您可以检查 Boost.Nowide(尚未包含在 Boost 中)以了解如何做到这一点: http ://cppcms.com/files/nowide/html/

使用 C++17,您可以使用 std::filesystem::path 以可移植的方式存储文件路径,但在 Windows 上仍然存在问题:

  • 隐式构造函数 std::filesystem::path::path(const char *) 在 MSVC 上使用用户特定的语言环境,并且无法使其使用 UTF-8。函数 std::filesystem::u8string 应该用于从 UTF-8 字符串构造路径,但是很容易忘记这一点并改用隐式构造函数。
  • std::error_category::message(int) 对于两个错误类别都使用用户特定的编码返回错误描述。

所以我们在 Windows 上拥有的是:

  • 打开文件的标准库函数已损坏,不应使用。
  • 传递给 main(int, char**) 的参数已损坏,不应使用。
  • 以 *A 和宏结尾的 WinAPI 函数已损坏,不应使用。
  • std::filesystem::path 部分损坏,切勿直接使用。
  • std::generic_categorystd::system_category 返回的错误类别已损坏,不应使用。

如果您需要一个重要项目的长期解决方案,我建议:

  • 使用 Boost.Nowide 或直接实现类似的功能 - 这修复了损坏的标准库。
  • 重新实现由 std::generic_categorystd::system_category 返回的标准错误类别,以便它们始终返回 UTF-8 编码的字符串。
  • 包装 std::filesystem::path 以便新类在将路径转换为字符串并将字符串转换为路径时始终使用 UTF-8。
  • 包装来自 std::filesystem 的所有必需函数,以便它们使用您的路径包装器和错误类别。

不幸的是,这不会解决与文件一起使用的其他库的问题,但无论如何很多都被破坏了(不支持 unicode)。

您可以查看此链接以获得进一步的解释: http ://utf8everywhere.org/

原文由 user1143634 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题