C++并不支持Unicode,即使是utf8

时至今日,字符串使用unicode已经是不需要理由的常识,但对一些有着悠久历史的编程语言来说,这仍然是个头痛的问题。如果抛开第三方库的支持,C++其实并不能实际有效地支持unicode,即使是utf8。(注:本文讨论的是字符串在内存中的编码方案,而不是文件或网络数据流。)

STL的string模板诞生时,unicode还是理想中的固定16位编码。那时,Windows、Java等先后跨跃进unicode时代,而Unix/Linux受限于向后兼容而难以改变。那时Windows上的C++编程主要用用Win32 API,还不流行STL,而Unix/Linux上还基本不支持Unicode。STL的wstring,只是将char模板参数替换成wchar_t,看起来似乎完全合理,其实并没有经过实践检验。所以,Windows上的wstring至今一直处于实际上不可用的状态,各种IO时的编码转换都有问题;而Linux上的wchar_t是32位,太浪费内存所以完全不值得使用。(最新的标准针对unicode引入了char16_t和char32_t,以及u16string和u32string。)

为什么Linux上的wchar_t是32位呢?因为gcc开始支持宽字符的时候,大约也是unicode的字符集突破16位编码极限的时候。本来预期非常充足的码位,出乎意料的不够了,unicode不得不做出调整。调整后,有了三种可选的unicode编码:
    utf32:一个码位固定4字节,一个码位表示一个字符编码。
    utf16:兼容之前的16位编码,一个码位2字节,但1或2个码位表示一个字符编码。
    utf8:兼容ASCII编码,一个码位1字节,但1到6个码位表示一个字符编码。(现行标准其实要求最多4个码位,但出于保障兼容性的原因,5、6个码位的情况是可能出现的,即使这算无效编码。)
    (除此之外,还有字符组合和修饰符组合的情况,使得码位到字符的映射更加复杂,在此忽略。)
    
utf8的出现,让Linux系统发现了新的机会,既然兼容ASCII,那么只要系统的编码页新加一个utf8的,不就支持unicode了么。很自然的,Linux就走了这条路。而Windows却不支持utf8的编码页,这让很多写跨平台程序的人对微软很是不满。而后,更有人宣称,Windows、Java、.NET等选错了unicode编码,utf8才是王道。

我很希望字符编码有个完美的解决方案,但很可惜,每当我们试图让它变得简单,它就变得更加复杂。最基本的问题:一个utf8编码的char数组,只不过是一个字节buffer,在C/C++的标准库支持下,你根本无法把它当字符串来处理。想要字符串长度?它只能给你字节数,而不是字符数。想要取第n个字符?它只能给你第n个字节。想要把一个字符转大写?想判断一个字符是否是字母?它只接受char类型的字符,也就是说只支持ASCII字符……

即使说对一个不需要操作字符的程序,在C/C++程序里我们总是要为输入分配buffer的,那么预期输入n个字符的buffer,应该分配多少字节呢?没错,你只能按最大可能n*6+1来分配。对内存临时分配还好,要是一个数据库字段,你怎么办?这时即使是utf32都可能更省存储空间。

当然,绝大多数问题都可以通过使用一个第三方的unicode库来解决。如果觉得专门的unicode库太heavy,至少还有boost的日常解决方案,只要把所有字符串操作替换成专门的函数……(如果安全性对你的程序很重要,你还要了解所用函数在遇到无效编码时的行为,因为这也是黑客突破安全检查的一种手段。)

但是,大多数的程序员甚至并不清楚unicode编码,更不可能了解编码转换的复杂性,他们或者习惯了C风格的字节操作,或者来自Java等使用双字节unicode的语言,做着并非字处理的软件,所以对学习复杂的unicode编码系统并无太大兴趣。所以,utf8在C/C++里,更象是专家级的解决方案,而并非面向普通开发者。理想情况下,C++可以凭借其强大的抽象和封装能力,包装出一个真正基于字符访问的字符串类(Python3走了这条路,但有很多批评的声音),然而现实中则很难将其标准化。

那么Windows、Java、.NET、iOS等所使用的utf16呢?本质上,他们的支持都是有缺陷的。因为他们开始时支持的其实是utf16的前身UCS2,每个字符固定2字节,而当utf16出现后,就权当UCS2用,也就是说双码位4字节的字符(unicode里称作BMP以外的字符)会被当作两个字符处理。如果你的程序真的想要正确支持双码位的字符,就要改写程序,使用高级字符串函数来访问字符串,而不是直接用下标索引。只是因为BMP以外的字符极其罕用,其程序员并不急需了解这些细节。从正确性角度来说,这并不正确,但从实用角度来说,还算实用。

http://blog.csdn.net/nightmare/article/details/39780931#comments

时间: 2024-12-21 15:42:28

C++并不支持Unicode,即使是utf8的相关文章

C++不支持Unicode,即使utf8

今天,字符串unicode我们已经不需要常理的理由,但是,一些有编程语言的悠久历史.这仍然是一个头疼. 尽管第三方库支持的假设,C++事实上没有真正有效地支持unicode.即使utf8.(注意:本文讨论了在内存中的字符串编码方案,络数据流.) STL的string模板诞生时,unicode还是理想中的固定16位编码.那时.Windows.Java等先后跨跃进unicode时代,而Unix/Linux受限于向后兼容而难以改变.那时Windows上的C++编程主要用用Win32 API,还不流行S

C++ Builder 的 JSON 解析和生成,包括自带的 JSON 和第三方的 jsoncpp,支持 UNICODE (UTF-8 / UTF-16)

C++ Builder 自带的 JSON 处理,支持 UNICODE (UTF-8 / UTF-16): http://www.cppfans.com/cbknowledge/skills/files/json.asp JSON 解析和生成 - 文件处理 ? JSON 解析方法和规则,读取 JSON 里面特定的值,JSON 类的继承关系 ? JSON 类 TJSONValue|TJSONObject|TJSONPair|TJSONArray|TJSONString|TJSONNumber|TJS

Python中的Unicode编码和UTF-8编码

下午看廖雪峰的Python2.7教程,看到 字符串和编码 一节,有一点感受,结合崔庆才的Python博客 ,把这种感受记录下来: ASCII码:是用一个字节(8bit, 0-255)中的127个字母表示大小写字母,数字和一些符号.主要用来表示现代英语和西欧语言. 所以处理中文就出现问题了,因为中文处理至少需要两个字节,所以中国制定了GB2312. 所以,各国制定了各国的标准.日本制定了Shift_JIS,韩国制定了Euc-kr...那么,乱码就来了. 为了统一,Unicode诞生了.统一码把所有

NET Framework 4.5新特性 (二) 控制台支持 Unicode (UTF-16) 编码

从 .NET Framework 4.5 开始,Console 类支持与 UnicodeEncoding 类的 UTF-16 编码.  显示 Unicode 字符到控制台,你可以设置 OutputEncoding 属性为 UTF8Encoding 或 UnicodeEncoding. 下面的示例显示 Unicode 字符的范围到控制台中.  该示例接受三个命令行参数:显示范围的开头,显示范围的末尾,以及是否使用当前控制台编码 (false) 或 UTF-16 编码 (true).  假定控制台使

从ASCII到Unicode再到UTF-8的历史原由

编码 大小 支持语言 ASCII 1个字节 英文 Unicode 2个字节(生僻字4个) 所有语言 UTF-8 1-6个字节,英文字母1个字节,汉字3个字节,生僻字4-6个字节 所有语言 具体解释: 最早只有127个字母被编码到计算机里,也就是大小写英文字母.数字和一些符号,这个编码表被称为ASCII编码,比如大写字母A的编码是65,小写字母z的编码是122. 但是要处理中文显然一个字节是不够的,至少需要两个字节,而且还不能和ASCII编码冲突,所以,中国制定了GB2312编码,用来把中文编进去

浅谈ASCII码、unicode编码、UTF-8编码的区别

字符集:是一堆字符组成的集合,用来指定字节或者字符串映射成二进制的规则 (在计算机中存储的,无论是字节还是字符串都是以二进制模式存储的.) ASCII编码和Unicode编码的区别: ASCII编码是1个字节,而Unicode编码通常是2个字节(2-4个字节). 字母A用ASCII编码是十进制的65,二进制的01000001: 字符0用ASCII编码是十进制的48,二进制的00110000,注意字符'0'和整数0是不同的: 汉字"中"已经超出了ASCII编码的范围,用Unicode编码

使你的C/C++代码支持Unicode(CRT字符串处理的所有API列表,甚至有WEOF字符存在)

悉Microsoft支持Unicode的方式. 它的主要目的是方便你查询相关的数据类型和函数,以及修正相应的拼写错误. I18nGuy 主页 XenCraft (Unicode 咨询公司) English My thanks to Yaker Gong for the translation to Chinese. Xie Xie! 使你的C/C++代码支持Unicode的第一步 定义宏 _UNICODE, 如果定义了宏 _MBCS 则取消它的定义(undefine). 在字符串前添加 L 标记

Unicode编码和utf-8编码的区别

字符集:是一堆字符组成的集合,用来指定字节或者字符串映射成二进制的规则 (在计算机中存储的,无论是字节还是字符串都是以二进制模式存储的.) 1    Unicode编码的由来 因为计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理.最早的计算机在设计时采用8个比特(bit)作为一个字节(byte),所以,一个字节能表示的最大的整数就是255 由于计算机是美国人发明的,因此,最早只有127个字符被编码到计算机里,也就是大小写英文字母.数字和一些符号,这个编码表被称为ASCII编码

用PHP将Unicode 转化为UTF-8

function?unescape($str) { ????$str?= rawurldecode($str); ????preg_match_all("/(?:%u.{4})|&#x.{4};|&#\d+;|.+/U",$str,$r); ????$ar?= $r[0]; ????//print_r($ar); ????foreach($ar?as?$k=>$v) { ????????if(substr($v,0,2) == "%u"){ ?