现代C++语言核心特性解析
上QQ阅读APP看书,第一时间看更新

1.2.1 字符集和编码方法

通常我们所说的字符集是指系统支持的所有抽象字符的集合,通常一个字符集的字符是稳定的。而编码方法是利用数字和字符集建立对应关系的一套方法,这个方法可以有很多种,比如Unicode字符集就有UTF-8、UTF-16和UTF-32这3种编码方法。除了Unicode字符集,我们常见的字符集还包括ASCII字符集、GB2312字符集、BIG5字符集等,它们都有各自的编码方法。字符集需要和编码方式对应,如果这个对应关系发生了错乱,那么我们就会看到计算机世界中令人深恶痛绝的乱码。不过,现在的计算机世界逐渐达成了一致,就是尽量以Unicode作为字符集标准,那么剩下的工作就是处理UTF-8、UTF-16和UTF-32这3种编码方法的问题了。

UTF-8、UTF-16和UTF-32简单来说是使用不同大小内存空间的编码方法。

UTF-32是最简单的编码方法,该方法用一个32位的内存空间(也就是4字节)存储一个字符编码,由于Unicode字符集的最大个数为0x10FFFF(ISO 10646),因此4字节的空间完全能够容纳任何一个字符编码。UTF-32编码方法的优点显而易见,它非常简单,计算字符串长度和查找字符都很方便;缺点也很明显,太占用内存空间。

UTF-16编码方法所需的内存空间从32位缩小到16位(占用2字节),但是由于存储空间的缩小,因此UTF-16最多只能支持0xFFFF个字符,这显然不太够用,于是UTF-16采用了一种特殊的方法来表达无法表示的字符。简单来说,从0x0000~0xD7FF以及0xE000~0xFFFF直接映射到Unicode字符集,而剩下的0xD800~0xDFFF则用于映射0x10000~0x10FFFF的Unicode字符集,映射方法为:字符编码减去0x10000后剩下的20比特位分为高位和低位,高10位的映射范围为0xD800~0xDBFF,低10位的映射范围为0xDC00~0xDFFF。例如0x10437,减去0x10000后的高低位分别为0x1和0x37,分别加上0xD800和0xDC00的结果是0xD801和0xDC37。

幸运的是,一般情况下0xFFFF足以覆盖日常字符需求,我们也不必为了UTF-16的特殊编码方法而烦恼。UTF-16编码的优势是可以用固定长度的编码表达常用的字符,所以计算字符长度和查找字符也比较方便。另外,在内存空间使用上也比UTF-32好得多。

最后说一下我们最常用的UTF-8编码方法,它是一种可变长度的编码方法。由于UTF-8编码方法只占用8比特位(1字节),因此要表达完数量高达0x10FFFF的字符集,它采用了一种前缀编码的方法。这个方法可以用1~4字节表示字符个数为0x10FFFF的Unicode(ISO 10646)字符集。为了尽量节约空间,常用的字符通常用1~2字节就能表达,其他的字符才会用到3~4字节,所以在内存空间可以使用UTF-8,但是计算字符串长度和查找字符在UTF-8中却是一个令人头痛的问题。表1-1展示了UTF-8对应的范围。

▼表1-1