小记:从广东玩回来寒假也差不多快没了,离开学不久,呆在家里太闲了,稍微看了点CSAPP,第二章的show_bytes和旁注,对Unicode和UTF-8,UTF-16这些东西产生了兴趣,原来还没有彻底搞明白这些东西是什么,看了点别人写的博客加之以实践,略有体会,小小的总结一下。
===============================================以下正文================================================
- Unicode是一种字符集,由2个字节构成,从0000 0000 ~7FFF FFF,每个数字代表一个字符。它不是一种编码方式,而是数字与字符对应的统一表。
- UTF-16是对Unicode的直接实现,根据Unicode对每个字符的编码来存储字符,大部分由2个字节构成,超过2个字节用4个字节构成,不兼容ASCII码,它受到大端小端法的影响。
- UTF-8是对Unicode不同方式的实现,利用自己的规则进行编码,优点是使得128个常用字符可以只用1个字节来储存,缺点是存储其他字符需要用到2-6个字节。
因为UTF-16是对Unicode的直接实现,所以对其编码方式没什么好说的,百度百科UTF-8中的一张表吸引了我的兴趣:
Unicode | bit数 | UTF8 | byte数 |
0000 0000 ~
0000 007F
| 0~7 | 0XXX XXXX | 1 |
0000 0080 ~
0000 07FF
| 8~11 |
110X XXXX
10XX XXXX
| 2 |
0000 0800 ~
0000 FFFF
| 12~16 |
1110 XXXX
10XX XXXX
10XX XXXX
| 3 |
0001 0000 ~
001F FFFF
| 17~21 |
1111 0XXX
10XX XXXX
10XX XXXX
10XX XXXX
| 4 |
0020 0000 ~
03FF FFFF
| 22~26 |
1111 10XX
10XX XXXX
10XX XXXX
10XX XXXX
10XX XXXX
| 5 |
0400 0000 ~
7FFF FFFF
| 27~31 |
1111 110X
10XX XXXX
10XX XXXX
10XX XXXX
10XX XXXX
10XX XXXX
| 6 |
UTF-8的编码很巧妙,可以看到,在Unicode值在0000 007F之前UTF-8都和Unicode的第二个数字一样,它只用了1个字节,而这128个字符是最常用的控制符和拉丁文字,相比于UTF-16用2个字节编码,在全英文的状况下是大大节省了空间,http://baike.baidu.com/view/40801.htm可以看到Unicode对不同文字所用的区域。
当超出128个字符时,UTF-8利用2个字节编码,但是,用UTF-8规则读取一段内存的时候如何知道它是用1个字节还是多个字节编码的呢?UTF-8的解决办法是在首字节的开头位用1来标示对于这一个字符需要读取几个字节,如上图所示。当读取到1110 XXXX这个信息后,就知道包括这个字节在内的接下来3个字节包含了一个字符的信息。这种办法的优点在于可以将最常用的字符用1个字节储存减少空间占用,取而代之的其他字符就需要用更多的字节来编码,UTF-16比UTF-8多利用的就是UTF-8前面的标示读取几个字节的位,所谓有得必有失。
利用CSAPP书上的一个例子,可以简单的查看UTF-8的具体编码。
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef unsigned char *byte_pointer; void show_bytes(byte_pointer start, int len) { int i; for (i = 0; i < len; i++) printf(" %.2x", start[i]); printf("\n"); } int main() { const char* s1 = "我我是是超超威威蓝蓝猫猫猫猫"; const char* s2 = "aabbAABB"; show_bytes ( (byte_pointer)s1,strlen(s1)+1); printf("\n\n"); show_bytes ( (byte_pointer)s2,strlen(s2)+1); system("pause"); return 0; }
输出结果是:
e6 88 91 e6 88 91 e6 98 af e6 98 af e8 b6 85 e8 b6 85 e5 a8 81 e5 a8 81 e8 93 9d e8 93 9d e7 8c ab e7 8c ab e7 8c ab e7 8c ab 00
61 61 62 62 41 41 42 42 00
可以看出来“我是超威蓝猫”这几个汉字是用3个字节编码的,而abAB是用2个字节编码的。记得很早以前貌似是小学的计算机课就学过汉字占2个字节,那是在GB编码下的,GB编码专门用于汉字的编码并且兼容ASCII,相比于UTF-8的3个字节的汉字,GB显然减少了空间占用。