豁然开朗,终于理顺了Unicode、utf-8等之间的关系,一直都是糊里糊涂的,知道今天看到了下面这篇文章!
http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
弄计算机这一行,就必须懂得一点字符编码的知识。
ASCII码:
一个字节有8个二进制位,对应256种状态,每种状态对应一个符号,就有256个符号。从0000 0000到1111 1111.
ASCII码,一共规定了128个字符,如A为65等等。这128个字符,只占用了一个字节的后7位,所以第一位就为0了。
对于英语,用128个符号编码就足够了。
非ASCII编码
对于其他语言,128个符号是不够的。有的语言可以利用128~255这一段,如法语,希伯来语等。但是这样又会带来新的问题。虽然都是使用256个符号的编码方式,但不同的国家有不同的字母。
更别说亚洲国家的文字,要求的符号就更多了,其中汉字就达10万之多。一个字节肯定是不够的,就必须用多个字节才能表示一个符号。比如,常见的中文编码GB2312。使用两个字节表示一个汉字,理论上可以表示256*256个汉字。
正因为得多个字节表示一个符号,才有了Unicode。
Unicode
Unicode是一个符号集,可以将世界上所有的符号容纳其中。每个符号给予一个独一无二的编码,那么就可以解决乱码问题。如U+4E25代表汉字‘严’。
注意:Unicode只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储(见番外_大端与小端)。
但是Unicode会带来问题,啥问题呢?比如英文字符只要一个字符,汉字‘严’,4E25,这个符号要两个字符;还有更大的字符,需要三个字符甚至4个字符。问题就是这些字符怎么区分到底是几个字节呢?
另外,若是统一存放字节数。即每个字符均用相同的字符数,方便是方便,但这对存储会造成极大的浪费。比如,本来一个字符的,硬要存3个或4个字符,文件就会比原来大小大二三倍。这显然是无法接受的。
UTF-8
everything is gonna be fine。
UTF-8就是Unicode的一种实现方式。其他实现方式UTF-16(2或4字节)和UTF-32(4字节)
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">UTF-8是一种变长的编码方式。可以使用1~4个字节来表示一个符号,适应性很强,是互联网使用最强的编码方式。</span>
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">下面是UTF-8的编码规则:</span>
Unicode编码(十六进制) | UTF-8 字节流(二进制) |
000000 - 00007F | 0xxxxxxx |
000080 - 0007FF | 110xxxxx 10xxxxxx |
000800 - 00FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
010000 - 10FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
还是拿汉字严为例:4E25(01001110 00100101),属于(000800~00FFFF)段,因此‘严’编码需要三个字节,即11100100 10111000 10100101,转成16进制是E4B8A5。
UTF-16
因为这个字超过U+FFFF所以无法用UCS-2的格式编码
16进制编码范围 | UTF-16表示方法(二进制) | 10进制码范围 | 字节数量 |
U+0000---U+FFFF | xxxxxxxx xxxxxxxx yyyyyyyy yyyyyyyy | 0-65535 | 2 |
U+10000---U+10FFFF | 110110yyyyyyyyyy 110111xxxxxxxxxx | 65536-1114111 | 4 |
UTF-16比起UTF-8,好处在于大部分字符都以固定长度的字节(2字节)存储,但UTF-16却无法兼容于ASCII编码。(来源维基)
番外:大端与小端
考虑一个2字节整数,在内存中存储这个数有两种方法:一种是将低字节放于起始地址,称为小端(little endian),另一种就是将高字节放于起始地址,称为大端(big endian)。IP协议使用大端字节序传送数据。本地的使用方式可能不同,看具体的硬件实现。
判断主机大端小端的程序:(来源于UNIX网络编程)
int main(){
union{
short s;
charc[sizeof(short)];
}un;
un.s = 0x0102;
if(sizeof(short)== 2){
if(un.c[0] == 1 && un.c[0] == 2){
printf(“big endian”);
}else if(un.c[0] == 2 && un.c[0] == 1)){
printf(“little endian”);
}else
printf(“unknown\n”);
}else
printf(“sizeof(short)=%d\n”, sizeof(short));
exit(0);
}