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

时间:2017-08-14 15:17:30

标签: c++

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

3 个答案:

答案 0 :(得分:10)

绝不使用wchar_t

如果可能,请使用(某种数组)char,例如std::string,并确保它以UTF-8编码。

如果必须与不使用UTF-8的API进行交互,请使用char16_tchar32_t。否则不要使用它们;它们只提供虚幻的优势,并鼓励错误的代码。

请注意,很多的情况需要多个char32_t来表示单个用户可见字符。 OTOH,使用带char的UTF-8强迫你很早就处理可变宽度。

答案 1 :(得分:7)

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

<强>背景
char类型具有足够的容量来保存ASCII字符集中的任何字符(编码)。

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

wchar_t,a.k.a。宽字符,为编码提供了更多空间。

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

首选Unicode来处理大字符集(例如emojis)。

答案 2 :(得分:7)

简短的回答:

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

答案很长:

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

在C ++程序中,您有两个区域设置: - std::setlocale设置的标准C库区域设置 - std::locale::global

设置的标准C ++库区域设置

不幸的是,它们都没有定义打开文件的标准函数的行为(如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上使用非标准Windows特定功能(如_wfopenstd::fstream::open(const wchar_t *)的自定义包装器。您可以查看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中包含所有必需的功能,以便他们使用您的路径包装器和错误类别。

不幸的是,这不会解决其他使用文件的库的问题,但是其中99%都会被破坏(不支持unicode)。

这就是C ++程序员的生活。 Microsoft可以通过允许我们将Windows运行时切换到基于UTF-8的语言环境来解决这个问题,但由于向后兼容性,它们不会这样做。

您可以查看此链接以获取进一步说明:http://utf8everywhere.org/