了解字符集

了解字符集
通过本文可以让你了解下字符集的基本概念。
Big Endian和Little Endian
上面提到了一个字符可能占用多个字节,那么这多个字节在计算机中如何存储呢? 比如字符0xabcd,它的存储格式到底是 AB CD,还是 CD AB 呢?
实际上两者都有可能,并分别有不同的名字。如果存储为 AB CD,则称为Big Endian; 如果存储为 CD AB,则称为Little Endian。
具体来说,以下这种存储格式为Big Endian,因为值(0xabcd)的高位(0xab)存储在前面:
例如 “中”的unicode码为4E2D。
若通过uedit查看16进制为4E2D,为Big Endian
相反,通过uedit查看16进制为2D4E,为Little Endian
gb2312
GB 系列是由中国国标局发布的字符编码方案(其中 GBK 不是正式标准),后期发布的版本兼容之前的,是之前的超集。(包括ASCII)
区位码
        区位码也就是国标码。所谓“国标码”,是指国家标准汉字编码。一般是指国家标准局1981年发布的《信息交换用汉字编码字符集(基本集)》,简称GB-2312。
在这个集中,收进汉字6763个,其中一级汉字3755个,二级汉字3008个。一级汉字为常用字,按拼音顺序排列,二级汉字为次常用字,按部首排列。
    GB-2312中,把没字分为94个区,每个区94个位。每个收进的汉字有一个因定的区位。例如“啊”字,位于16区,01位,这个区号和位号就构成了它的区位码“1601”。这就是我上面说的,区位码就是国标码。
内码
    内码是保存在计算机中或文件中的汉字编码。它是十六进制的(当然在机器中是二进制了)。
例如:汉字“中”的gb2312编码的内码是D6D0,其区位码是5448(说明它在gb2312表的54区第48个)
gb2312区位码到内码的转换:需要在高字节和低字节上分别加上A0
(因为ASCII的基本集只有128个,编号为0-127;而十六进投影的“A0”,换算为十进制,就是“160”了,这样就不会和ASCII的基本集相冲突了。)

从程序员的角度,其实我们只要关注内码就好了。

GB2312区位码全表
http://www.mytju.com/classCode/tools/QuWeiMa_FullList.asp
GB2312简体中文编码表(内码)
http://www.knowsky.com/resource/gb2312tbl.htm
Unicode、UCS和UTF
Unicode也是一种字符编码方法,不过它是由国际组织设计,可以容纳全世界所有语言文字的编码方案。Unicode的 学名是"Universal Multiple-Octet Coded Character Set",简称为UCS。UCS可以看作是"Unicode Character Set"的缩写。
UCS规定了怎么用多个字节表示各种文字。怎样传输这些编码,是由UTF(UCS Transformation Format)规范规定的,常见的UTF规范包括UTF-8、UTF-7、UTF-16。
Unicode详解  http://tech.idv2.com/2008/02/21/unicode-intro/
UTF8编码的原理
UTF-8 是以8位为单元对 UCS-2 进行再次编码映射,是当前网络传输、存储优选的字符集。
因为一个字母还有一些键盘上的符号加起来只用二进制七位就可以表示出来,而一个字节就是八位,所以UTF8就用一个字节来表式字母和一些键盘上的符号。 然而当我们拿到被编码后的一个字节后怎么知道它的组成?它有可能是英文字母的一个字节,也有可能是汉字的三个字节中的一个字节!所以,UTF8是有标志位 的!
当要表示的内容是 7位 的时候就用一个字节:0*******  第一个0为标志位,剩下的空间正好可以表示ASCII 0-127 的内容。
当要表示的内容在 8 到 11 位的时候就用两个字节:110***** 10******  第一个字节的110和第二个字节的10为标志位。
当要表示的内容在 12 到 16 位的时候就用三个字节:1110***** 10****** 10******    和上面一样,第一个字节的1110和第二、三个字节的10都是标志位,剩下的空间正好可以表示汉字。
以此类推:
四个字节:11110**** 10****** 10****** 10******
五个字节:111110*** 10****** 10****** 10****** 10******
六个字节:1111110** 10****** 10****** 10****** 10****** 10******
这样,当读到一个111110***时,机器就会知道把接下来的4位再组合进来一起处理了。
utf-8编码转换例子
汉字“中”的utf-8编码
E4 B8 AD

换成2进制
11100100 10111000 10101101

还原成unicode码
0   0100  1110    0010   1101
4     E       2      D

如何处理源文件的字符集
使用如下文件(内部代码都相同,只是文件的字符集格式不同)分别编译后执行

GCC的工作方式直接了当:不管你源文件是什么编码,编译时只将两引号之间的字符串复制一份到对象文件中,参考:在 Linux C 编程中使用 Unicode 和 UTF-8。
从外部文件中读取的是什么格式,在其内存中也是什么格式。例如:有一个外部文件是utf-8的,其中有一个字“中”,那么在内存中也是“中”的utf-8码:E4 B8 AD

#include <iostream>
#include <bitset>
#include <string.h>

#define TMP_LEN 256

void printHex(unsigned char *ch,int len);
void printHex(wchar_t *wch);

int main(int argc,char* argv[])
{
        char *ch = "中国abc";
        printHex(ch,strlen(ch));
//        wchar_t *wch = L"中国abc";
//        printHex(wch);
}

void printHex(unsigned char *ch,int len)
{
    unsigned char tmp[TMP_LEN];
    memset(tmp,0,TMP_LEN);
    memcpy(tmp,ch,TMP_LEN);

    printf("%s/n",tmp);
    for(int i=0; i<len; i++)
        std::cout<<std::hex<<(unsigned int)tmp[i]<<"--";
    std::cout<<std::endl;
}

void printHex(wchar_t *wch)
{

        char tmp[TMP_LEN];
        memset(tmp,0,TMP_LEN);
        memcpy(tmp,wch,sizeof(wch));
       
        for(int i=0;i<TMP_LEN;i++)
        std::cout<<std::hex<<(unsigned int)tmp[i]<<"--";
        std::cout<<std::endl;
}

将上面代码的注释打开,测试wchar_t。
环境还是gcc4.4.3
发现只有源文件为utf-8和utf-8(bom) 才能编译通过。且在内存中编码都是UCS2 LE。源文件为GB2312无法通过编译。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值