【发布时间】:2013-10-29 03:36:28
【问题描述】:
C11 和 C++11 都引入了 uchar.h/cuchar 标头,将 char16_t 和 char32_t 明确定义为 16 位和 32 位宽字符,添加了用于编写字符串的文字语法 u"" 和 U""使用这些字符类型,以及告诉您它们是否对应于 UTF-16 和 UTF-32 代码单元的宏 __STDC_UTF_16__ 和 __STDC_UTF_32__。这有助于消除关于 wchar_t 的歧义,在某些平台上是 16 位,通常用于保存 UTF-16 代码单元,而在某些平台上是 32 位,通常用于保存 UTF-32 代码单元;假设现在设置了这些宏,您现在可以编写引用 UTF-16 和 UTF-32 的可移植、明确的代码。 __STDC_ISO_10646__ 也可以用作代理来确定wchar_t 是否能够保存 UTF-32 值;如果不能,您不一定能假定它拥有 UTF-16,但它可能是一个足够接近的近似值,可以移植。
他们还添加了函数mbrtoc16、mbrtoc32、c16rtomb和c32rtomb,用于在多字节字符和这些类型之间进行转换。在这些和现有的mbstowcs 系列函数之间,可以在 UTF-16、UTF-32、平台多字节字符集和平台宽字符集之间进行可移植的转换(尽管不一定无损,除非平台定义了多字节和宽字符集是 UTF;特别是,这些函数在 Windows 上似乎毫无用处,因为语言环境定义的多字节编码不允许每个字符使用超过两个字节)。
此外,他们添加了 u8"" 语法来编写文字 UTF-8 编码字符串。由于 UTF-8 是一种与处理char * 和std::string 的大多数函数兼容的编码,因此这是最有用的新增功能之一。
但是,他们似乎没有添加任何方法来在 UTF-8、UTF-16 和 UTF-32 之间进行可移植转换。 mbtoc16 和相关函数在实现定义的多字节编码和 UTF-16 或 32 之间进行转换;但你不能依赖这是 UTF-8。在类 Unix 平台上,它依赖于语言环境,其中许多默认情况下在其语言环境中使用 UTF-8,即使它不是默认设置,您至少可以将语言环境设置为 UTF-8 语言环境以了解“多字节”表示 UTF-8。但是,在 Windows 上,您 explicitly can't use UTF-8 or any other encoding that requires more than two bytes for the locale。
我只是遗漏了什么,还是 UTF-8 字符串类型没有伴随任何方式将其转换为其他类型的字符串:平台定义的多字节、平台定义的宽字符、UTF-16 或 UTF-32?甚至无法判断您的系统多字节编码是否为 UTF-8?是否有任何理由不包括这种支持(具体来说,我正在寻找 C 或 C++ 标准委员会的实际书面理由或讨论,而不仅仅是猜测)?是否正在做任何工作来改善这种情况?以后有可能改进吗?
或者,如果您想以可移植的方式支持 UTF-8、编写自己的实现、引入库依赖项或使用特定于平台的函数(如 iconv 和 MultiByteToWideChar),或者,这是当前最好的解决方案?
【问题讨论】:
-
请注意,这个问题与WChars, Encodings, Standards and Portability 非常相似,但我更感兴趣的是标准委员会的决定背后的推理,以及在以实际可行的方式标准化这一方面是否取得了进展,而不是“现在最好的方法是什么”。
-
"
__STDC_ISO_10646__也可以用作代理来确定 wchar_t 是否能够保存 UTF-32 值;"没有。例如,OS X 没有定义这个,但使用 UTF-32 来表示xx_XX.UTF-8语言环境。它没有定义宏的原因是因为对于非 .UTF-8 语言环境,它可能使用非 UTF-32 编码。如果您想知道使用 UTF-32 的语言环境,您只需了解特定于该语言环境的信息。如果您想知道是否可以将 wchar_t 用于您自己的 UTF-32 数据和例程,那么您只需要确保sizeof(wchar_t)*CHAR_BIT >= 21. -
@bames53 叹息,你是对的。看来连这个都靠不住了。所以我想知道的是:为什么这不是标准化的?编写一个实际上允许您编写涉及 Unicode 的实际可移植代码的标准有什么障碍?现在,这个标准几乎没用。您需要分别为每个平台编写代码。这是他们实际尝试过但失败的事情,还是只是没有人对在 C 中标准化一组实际有用的 Unicode 例程特别感兴趣?
-
我想最大的问题之一是每个平台都已经有了某种处理方式,而标准化某些东西会与现有的一种或另一种实现发生冲突。避免这种情况的唯一方法可能是标准化一个与现有标准功能无关的 Unicode 库。
-
这意味着,例如,
fopen()的新版本。这是因为要可移植地使用 UTF-8,必须指定此类库组件采用什么编码,目前还没有这样做。在某些平台上 fopen 采用系统语言环境多字节编码,在某些平台上采用任意字节序列,在某些平台上采用 UTF-8 而与语言环境无关。
标签: c++11 unicode utf-8 character-encoding c11