gpt4 book ai didi

c++ - C++ wchar_t 和 wstrings 的 "wrong"是什么?宽字符有哪些替代方案?

转载 作者:行者123 更新时间:2023-12-01 18:27:02 25 4
gpt4 key购买 nike

我看到 C++ 社区中有很多人(尤其是 freenode 上的##c++)对 wstrings 的使用表示不满。和 wchar_t ,以及它们在 windows api 中的使用。 wchar_t究竟有什么“错误”?和 wstring ,如果我想支持国际化,宽字符有哪些替代方案?

最佳答案

wchar_t 是什么?

wchar_t 的定义使得任何语言环境的 char 编码都可以转换为 wchar_t 表示,其中每个 wchar_t 仅表示一个代码点:

Type wchar_t is a distinct type whose values can represent distinct codes for all members of the largest extended character set specified among the supported locales (22.3.1).

                                                                               — C++ [basic.fundamental] 3.9.1/5



这不需要 wchar_t 足够大以同时表示来自所有语言环境的任何字符。也就是说,用于 wchar_t 的编码可能因地区而异。这意味着您不一定使用一种语言环境将字符串转换为 wchar_t,然后使用另一种语言环境将其转换回 char。1

由于使用 wchar_t 作为所有语言环境之间的通用表示似乎是 wchar_t 在实践中的主要用途,因此您可能想知道如果不是这样,它有什么好处。

wchar_t 的最初意图和目的是通过定义文本来简化文本处理,使其需要从字符串的代码单元到文本字符的一对一映射,从而允许使用与所使用的相同的简单算法与 ascii 字符串一起使用其他语言。

不幸的是,wchar_t 规范的措辞假设字符和代码点之间存在一对一的映射来实现这一点。 Unicode 打破了这个假设2,因此您也不能安全地将 wchar_t 用于简单的文本算法。

这意味着可移植软件不能将 wchar_t 用作语言环境之间文本的通用表示,也不能使用简单的文本算法。

wchar_t 今天有什么用?

无论如何,对于可移植代码来说并不多。如果定义了 __STDC_ISO_10646__,则 wchar_t 的值直接表示在所有语言环境中具有相同值的 Unicode 代码点。这使得进行前面提到的区域间转换是安全的。但是,您不能仅仅依靠它来决定您可以以这种方式使用 wchar_t,因为虽然大多数 unix 平台都定义了它,但即使 Windows 在所有语言环境中使用相同的 wchar_t 语言环境,Windows 也不会。

Windows 没有定义 __STDC_ISO_10646__ 的原因是因为 Windows 使用 UTF-16 作为其 wchar_t 编码,并且因为 UTF-16 使用代理对来表示大于 U+FFFF 的代码点,这意味着 UTF-16 不满足 __STDC_ISO_10646__

对于平台特定的代码 wchar_t 可能更有用。它本质上在 Windows 上是必需的(例如,某些文件在不使用 wchar_t 文件名的情况下根本无法打开),尽管据我所知,Windows 是唯一正确的平台(所以也许我们可以将 wchar_t 视为“Windows_char_t”)。

事后看来, wchar_t 显然对于简化文本处理或作为独立于语言环境的文本的存储没有用。可移植代码不应试图将其用于这些目的。非可移植代码可能仅仅因为某些 API 需要它而发现它很有用。

替代品

我喜欢的替代方法是使用 UTF-8 编码的 C 字符串,即使在对 UTF-8 不是特别友好的平台上也是如此。

通过这种方式,人们可以使用跨平台的通用文本表示编写可移植代码,将标准数据类型用于其预期目的,获得语言对这些类型的支持(例如字符串文字,尽管需要一些技巧才能使其适用于某些编译器),某些标准库支持、调试器支持(可能需要更多技巧)等。使用宽字符通常更难或不可能获得所有这些,并且您可能会在不同平台上获得不同的部分。

UTF-8 没有提供的一件事是能够使用简单的文本算法,例如 ASCII 可能的。在这方面 UTF-8 并不比任何其他 Unicode 编码差。事实上,它可能被认为更好,因为 UTF-8 中的多代码单元表示更常见,因此与尝试坚持使用 UTF 相比,处理这种可变宽度字符表示的代码中的错误更有可能被注意到和修复-32 使用 NFC 或 NFKC。

许多平台使用 UTF-8 作为其原生字符编码,并且许多程序不需要任何重要的文本处理,因此在这些平台上编写国际化程序与不考虑国际化编写代码几乎没有什么不同。编写更广泛的可移植代码,或在其他平台上编写需要在使用其他编码的 API 的边界处插入转换。

某些软件使用的另一种替代方法是选择跨平台表示,例如保存 UTF-16 数据的无符号短数组,然后提供所有库支持并简单地承担语言支持等方面的成本。

C++11 添加了新的宽字符作为 wchar_t、char16_t 和 char32_t 的替代品,并具有附带的语言/库功能。这些实际上并不能保证是 UTF-16 和 UTF-32,但我不认为任何主要实现会使用其他任何东西。 C++11 还改进了 UTF-8 支持,例如使用 UTF-8 字符串文字,因此没有必要欺骗 VC++ 生成 UTF-8 编码字符串(尽管我可能会继续这样做而不是使用 u8 前缀)。

避免的替代方法

TCHAR:TCHAR 用于迁移采用传统编码的古老 Windows 程序,从 char 到 wchar_t,最好忘记,除非您的程序是在前一千年编写的。它不是可移植的,并且其编码甚至其数据类型本质上是不确定的,因此无法与任何基于非 TCHAR 的 API 一起使用。由于它的目的是迁移到 wchar_t,我们在上面看到这不是一个好主意,因此使用 TCHAR 没有任何值(value)。


1. 可以在 wchar_t 字符串中表示但在任何语言环境中都不支持的字符不需要用单个 wchar_t 值表示。这意味着 wchar_t 可以对某些字符使用可变宽度编码,这又明显违反了 wchar_t 的意图。尽管 wchar_t 可表示的字符足以说明语言环境“支持”该字符是有争议的,但在这种情况下,可变宽度编码是不合法的,并且 Window 对 UTF-16 的使用不符合标准。

2. Unicode 允许用多个代码点表示许多字符,这对于简单的文本算法和可变宽度编码产生了同样的问题。即使严格维护组合规范化,某些字符仍然需要多个代码点。见: http://www.unicode.org/standard/where/

关于c++ - C++ wchar_t 和 wstrings 的 "wrong"是什么?宽字符有哪些替代方案?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11107608/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com