C ++ wchar_t和wstrings有什么“错”?宽字符有哪些替代方法?


86

我看到很多人在C ++社区(freenode上特别是## C ++)怨恨使用wstringswchar_t,以及它们在Windows API的使用。究竟是什么“错误”有wchar_twstring,如果我想支持国际化,有一些什么替代宽字符?


1
有什么参考吗?
Dani 2012年

14
也许这个很棒的话题将回答您所有的问题?stackoverflow.com/questions/402283/stdwstring-vs-stdstring
MrFox 2012年

15
在Windows上,您实际上别无选择。它的内部API是为UCS-2设计的,这在当时是合理的,因为在可变长度UTF-8和UTF-16编码标准化之前。但是,既然他们支持UTF-16,他们最终陷入了两全其美的境地。
jamesdlin 2012年

12
utf8everywhere.org很好地讨论了避免使用宽字符的原因。
JoeG 2012年

5
@jamesdlin当然,您可以选择。nowide库提供了仅在传递给API时转换字符串的便捷方法。带字符串的API调用通常是低频的,因此合理的方法是转换ad-hok并始终使用UTF-8包含文件和内部变量。
帕维尔·拉兹维洛夫斯基

Answers:


114

什么是wchar_t?

定义wchar_t,以便可以将任何语言环境的char编码转换为wchar_t表示形式,其中每个wchar_t都恰好表示一个代码点:

wchar_t类型是一种独特的类型,其值可以代表受支持的语言环境(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__已定义if,则wchar_t的值直接表示在所有语言环境中具有相同值的Unicode代码点。这样可以安全地进行前面提到的区域间转换。但是,您不能仅依靠它来决定可以以这种方式使用wchar_t,因为尽管大多数Unix平台都定义了它,但是Windows并没有,即使Windows在所有语言环境中使用了相同的wchar_t语言环境。

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作为其本机char编码,许多程序不需要任何重要的文本处理,因此在那些平台上编写国际化程序与在不考虑国际化的情况下编写代码几乎没有什么不同。编写更广泛的可移植代码,或在其他平台上进行编写,则需要在使用其他编码的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毫无价值。


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

2. Unicode允许用多个代码点表示许多字符,这给简单文本算法带来了与可变宽度编码相同的问题。即使严格保持组合归一化,某些字符仍需要多个代码点。参见:http : //www.unicode.org/standard/where/


3
另外:utf8everywhere.org建议在Windows上使用UTF-8,并且Boost.Nowide计划进行正式审查。
Yakov Galka 2012年

2
当然,最好的方法是在Windows上使用C#或VB.Net :)或普通的C / Win32。但是,如果必须使用C ++,那么TCHAR是最好的选择。在MSVS2005及更高版本上默认为“ wchar_t”。恕我直言...
paulsm4 2012年

4
@BrendanMcK:当然,不存在使用Windows上的Win32 API和其他系统上的其他API的代码。对?微软的方法(“在应用程序的内部各处使用wchar”)的问题在于,它甚至会影响无法直接与系统接口并且可以移植的代码。
Yakov Galka 2012年

4
问题是您必须使用Windows特定的功能,因为Microsoft不支持将UTF-8作为ANSI代码页的决定“破坏了”标准C(++)库。例如,您不能fopen使用名称包含非ANSI字符的文件。
dan04 2012年

11
@ dan04是的,您不能在Windows上使用标准库,但是可以创建可移植的接口,该接口将标准库包装在其他平台上,并在使用Win32 W函数之前直接从UTF-8转换为wchar_t。
bames53 2012年

20

wchar_t没有任何“错误”。问题在于,在NT 3.x时代,Microsoft认为Unicode很好(现在),并且将Unicode实现为16位wchar_t字符。因此,大多数90年代中期的Microsoft文献都将Unicode == utf16 == wchar_t等同于Unicode。

不幸的是,事实并非如此。“宽字符”不是一定是2个字节,在所有平台上,在任何情况下。

这是我见过的有关“ Unicode”的最佳入门文章(独立于此问题,独立于C ++):我强烈建议这样做:

老实说,我认为处理“ 8位ASCII”与“ Win32宽字符”与“ wchar_t-in-general”的最佳方法就是接受“ Windows与众不同”并相应地进行编码。

恕我直言...

PS:

我完全同意上面的jamesdlin:

在Windows上,您别无选择。它的内部API是为UCS-2设计的,这在当时是合理的,因为在可变长度UTF-8和UTF-16编码标准化之前。但是,既然他们支持UTF-16,他们最终陷入了两全其美的境地。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.