Ken*_* Li 81 c++ unicode winapi internationalization wstring
我见过C++社区中的很多人(特别是freenode上的## c ++)对windows api 的使用wstrings和使用感到不满wchar_t.究竟是什么"错误"有wchar_t和wstring,如果我要支持国际化,有一些什么替代宽字符?
bam*_*s53 112
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用作语言环境之间文本的通用表示,也不能使用简单的文本算法.
对于便携式代码而言,并不多.如果__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没有任何价值.
1.在wchar_t字符串中可表示但在任何语言环境中不受支持的字符不需要用单个wchar_t值表示.这意味着wchar_t可以对某些字符使用可变宽度编码,另一种明显违反wchar_t的意图.虽然可以说wchar_t可表示的字符足以说该语言环境"支持"该字符,但在这种情况下,可变宽度编码是不合法的,并且Window使用UTF-16是不符合要求的.
2. Unicode允许用多个代码点表示许多字符,这为简单的文本算法创建了与可变宽度编码相同的问题.即使严格维护组合规范化,某些字符仍然需要多个代码点.见:http://www.unicode.org/standard/where/
pau*_*sm4 18
wchar_t没有"错误".问题是,在NT 3.x天,微软决定Unicode是好的(它是),并将Unicode实现为16位,wchar_t字符.因此,大多数90年代中期的微软文献几乎等同于Unicode == utf16 == wchar_t.
遗憾的是,事实并非如此."宽字符"是不是一定是2个字节,在所有平台上,在任何情况下.
这是关于"Unicode"的最好的引物之一(独立于这个问题,独立于C++)我见过:我强烈推荐它:
我真的相信处理"8位ASCII"与"Win32宽字符"与"wchar_t-in-general"的最佳方式只是接受"Windows不同"......并相应地编码.
恕我直言...
PS:
我完全赞同上面的jamesdlin:
在Windows上,您实际上没有选择.它的内部API是为UCS-2设计的,当时它是在可变长度UTF-8和UTF-16编码标准化之前的合理时间.但是现在他们支持UTF-16,他们最终得到了两个世界中最糟糕的一个.