编码的问题每次都是弄懂然后过后遇到有些小的细节又忘了,这次就整理一下吧,
原文的是:http://blog.sina.com.cn/s/blog_aa01f7030101np42.html,http://blog.csdn.net/sunshine1314/article/details/2309655
先提一下大小端序的问题:
big endian是指低地址存放最高有效字节(MSB),而little endian则是低地址存放最低有效字节(LSB)。采用big endian方式存储数据是符合我们人类的思维习惯的。
一个例子:
如果我们将0x1234abcd写入到以0x0000开始的内存中,则结果为
big-endian little-endian
0x0000 0x12 0xcd
0x0001 0x34 0xab
0x0002 0xab 0x34
0x0003 0xcd 0x12
比特序也是同样的
优劣:
Big Endian
判别一个数的正负很容易,只要取offset0处的一个字节就能确认。
Little Endian
长度为1,2,4字节的数,排列方式都是一样的,数据类型转换非常方便。
ASCII码
ASCII码使用指定的7位或8位二进制数组合来表示128或256种可能的字符。ASCII码分为标准ASCII码和扩展ASCII码。
标准ASCII码,使用7位二进制数来表示。其中:
在标准ASCII中,其最高位(b7)用作奇偶校验位。所谓奇偶校验,是指在代码传送过程中用来检验是否出现错误的一种方法,一般分奇校验和偶校验两种。
后128个称为扩展ASCII码。许多基于x86的系统都支持使用扩展(或“高”)ASCII。扩展ASCII 码允许将每个字符的第8位用于确定附加的128 个特殊符号字符、外来语字母和图形符号。
GB2312
GB2312基本集共收入汉字6763个和非汉字图形字符682个。整个字符集分成94个区,每区有94个位。每个区位上只有一个字符,用所在的区和位来对汉字进行编码,称为区位码。
GB2312中对所收汉字进行了“分区”处理,每区含有94个汉字/符号。这种表示方式也称为区位码。
举例来说,“啊”字是GB2312之中的第一个汉字,它的区位码就是1601,代表位于第16区,位码是01。
每个汉字及符号以两个字节来表示。第一个字节称为“高位字节”(也称“区字节)”,第二个字节称为“低位字节”(也称“位字节”)。“高位字节”使用了0xA1-0xF7(把01-87区的区号加上0xA0),“低位字节”使用了0xA1-0xFE(把01-94加上 0xA0)。一级汉字从16区起始,汉字区的“高位字节”的范围是0xB0-0xF7,“低位字节”的范围是0xA1-0xFE,占用的码位是 72*94=6768。其中有5个空位是D7FA-D7FE。
GBK编码
GBK编码是GB2312的扩展 ,除了兼容GB2312外,它还能显示繁体中文,还有日文。
全部编码分为三大部分
- GB 2312 汉字区。即 GBK/2: B0A1-F7FE。收录GB 2312汉字6763个,按原顺序排列。
- GB 13000.1 扩充汉字区。包括:
- GBK/3: 8140-A0FE。收录 GB 13000.1 中的 CJK 汉字 6080 个。
- GBK/4: AA40-FEA0。收录 CJK 汉字和增补的汉字 8160 个。
- GB 2312 非汉字符号区。即 GBK/1: A1A1-A9FE。其中除 GB 2312 的符号外,还有 10 个小写罗马数字和 GB 12345 增补的符号。计符号 717 个。
- GB 13000.1 扩充非汉字区。即 GBK/5: A840-A9A0。BIG-5 非汉字符号、结构符和“○”排列在此区。计符号 166 个。
ANSI编码
不同的国家和地区制定了不同的标准,由此产生了GB2312,JIS等各自的编码标准。这些使用2个字节来代表一个字符的各种汉字延伸编码方式,称为ANSI编码。
在简体中文系统下,ANSI编码代表 GB2312编码,在日文操作系统,ANSI编码代表JIS编码。 不同 ANSI 编码之间互不兼容,当信息在国际间交流时,无法将属于两种语言的文字,存储在同一段 ANSI 编码的文本中。
通常使用0x80~0xFF 范围(128之后)2个字节来表示1个字符。比如:汉字 '中' 在中文操作系统中,使用 [0xD6,0xD0] 这两个字节存储。对于ANSI编码而言,0x00~0x7F(127)之间的字符,依旧是1个字节代表1个字符。这一点是ANSI编码与Unicode(UTF-16)编码之间最大也最明显的区别。
比如“A君是第131号”,在ANSI编码中,占用12个字节,而在Unicode(UTF-16)编码中,占用16个字节。因为A和1、3、1这4个字符,在ANSI编码中只各占1个字节,而在Unicode(UTF-16)编码中,是需要各占2个字节的。
在ANSI编译期上,如果没有显示指定编码,默认使用的是ANSI编码,比如
strlen(str)返回4。
strlen(str)返回5。
Unicode(UTF-16)
Unicode只有一个字符集,它采用UCS-2,用两个字节来编码一个字符,2的16次方等于65536,最多能编码65536个字符。它前128个字符就是ASCII码(Unicode中也占用两个字节),之后是扩展码。汉文,韩语,日语的文字占用从0X3000到0X9FFF的代码。Unicode也有UCS-4规范,就是用 4个字节来编码字符。
Unicode只与ASCII兼容,与GB码不兼容。例如“汉”字的Unicode编码是6C49,而GB码是BABA。
UTF-8(8-bit Unicode Transformation Format)
UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,又称万国码。UTF-8用1到4个字节编码UNICODE字符。UTF-8最多可用到6个字节。
对于某一个字符的UTF-8编码,如果只有一个字节则其最高二进制位为0;如果是多字节,其第一个字节从最高位开始,连续的二进制位值为1的个数决定了其编码的位数,其余各字节均以10开头。
UTF-8编码转换为Unicode编码: 将所有标志位去除,剩余位数若不足则在高位补零,凑足32位即可
Unicode编码转换为UTF-8编码: 从低位开始,每取6位补两个位10,不足6位(不算高位的0)则按字节长度补相应的字符标志位0、110、1110等,如:
因此UTF-8中可以用来表示字符编码的实际位数最多有31位,即上表中x所表示的位。除去那些控制位(每字节开头的10等),这些x表示的位与UNICODE编码是一一对应的,位高低顺序也相同。
实际将UNICODE转换为UTF-8编码时应先去除高位0,然后根据所剩编码的位数决定所需最小的UTF-8编码位数。
基本ASCII字符集中的字符只需要一个字节的UTF-8编码(7个二进制位)便可以表示。
Unicode转换为UTF-8需要的字节数可以根据Unicode二进制的位数除以6(向上取整)来计算。
BOM(Byte Order Mark)字节顺序标记
在UCS编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。
UCS规范建议我们在传输字节流前,先传输字符"ZERO WIDTH NO-BREAK SPACE"。这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little- Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被称作BOM。
UTF-8UTF-8以字节为编码单元,没有字节序的问题,不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8编码是EF BB BF。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。
UTF-8编码的文件中,BOM占三个字节。如果用记事本把一个文本文件另存为UTF-8编码方式的话,用UE打开这个文件,切换到十六进制编辑状态就可以看到开头的FFFE了。这是个标识UTF-8编码文件的好办法,软件通过BOM来识别这个文件是否是UTF-8编码,很多软件还要求读入的文件必须带BOM。可是,还是有很多软件不能识别BOM。
当一个软件打开一个文本时,第一件事是决定这个文本究竟是使用哪种字符集的哪种编码保存的。软件一般采用三种方式来决定文本的字符集和编码:
字符串编码类型判断