多字节字符与宽字符
背景知识
字符是人们认识世界,用来标记的符号。但是计算机并不认识这些字符。
所以需要对这些字符进行编号,这样,字符与编码之间就形成了映射关系。当你输入65的时候,计算机才能识别,你其实想表达的是'A'.
常见的字符集:ANSI字符体系,Unicode字符体系
ANSI体系:ASCII字符集、GB2312字符集(主要用于处理中文汉字)、GBK字符集(主要用于处理中文汉字)
Unicode体系:Unicode字符集
编码:
ASCII字符集----ASCII编码
GB2312字符集----GB2312编码
GBK字符集---GBK编码
Unicode字符集(宽字符)----UTF8编码、UTF16编码、UTF32编码
在C/C++程序中,我们使用char类型来存储单个字符('0','A'),一般而言, char类型的长度是1个字节,共有8位。
也就是,一个char类型的变量ch,最多可以存储2^8=256个字符。
但是,随着字符的国际化,各个国家的字符标点,已经远超256个字符。由此,产生了一种解决方案。
多字节字符
多字节字符: 一般来说,一个char是1个字节,之所以教多字节字符是因为,一个char类型的变量,表示一个字符的时候,可能是一个字节,也可能是多个字节。
比如,你需要保存一个字符'A',已知字符'A'的编码是65,所以一个字节就可以表示。
但是,如果你想表达’赵'这个字符,他的unicode编码对应的是0xD5D4,1个字节就不够用了,因为汉字的编码大于256.
因此大家就是用多字节来表示一个字符来接觉得不够用的问题,但是前128个已经被占用了,具体可以查看ASCII编码。后来256也不够用了。
而且由此也产生一个问题,试想:假如你有一个字符串:
char ch[] = "abc赵钱孙123";
那么你解析的时候,最好能对每个字符做一个标识:
第一个字符a占用1个字节,
第二个字符b占用1个字节
第三个字符c占用1个字节
第四个字符赵,占用2个字节
第五个字符钱,占用2个字节
第六个字符孙,占用2个字节
第七个字符1,占用1个字节
...
这样下来,如果存储一个带有中英文的字符,会比较麻烦,因为,你需要额外的一个数组,来表示上面的字符数组的每个元素,所占用的字节,这样才能正常解析。
如此一来,简直太麻烦了。
宽字符
后来,宽字符应运而生。已知一个字节是8位,最多能表示256个字符,其实一个字节未必一定是8位的,也可以是16位,只不过大家用久了,默认都是一个字节是8位。
所以,宽字符,其实言外之意,是可以用多个字节表示一个字符的,也就是所有的字符都是多个字节,而不是原来只是超过256的字符。
比如,’赵‘这个字,用2个字节来表示,同样,‘A’也用两个字节来表示,这样虽然浪费了一部分内存空间(因为原来一个字节能表示的字符,现在都需要两个字节),但是,解析的时候会方便多了。
也就是,所有的字符,都假设按照两个字节来表示,2^16=65536,6万多个字符,足以表示全世界所有的符号了。
在C/C++中,宽字符类型wchar_t 它和我们熟悉的char类型是一样的,只不过,涉及宽字符的相关库函数,都要用宽字符类型的库函数来处理,一般有w作为前缀。名字和我们熟悉的差别并不大。
比如库函数strlen()对应的是wcslen()。
宽字符并不一定是Unicode,Unicode只是宽字符编码的一种实现。
它有三种常见的编码方式:UTF-8(1个字节表示)、UTF-16(2个字节表示)、UTF-32(4个字节表示).
int main(void)
{
std::string strLocale = setlocale(LC_ALL, "");
wchar_t *pw = L"赵钱孙A";
wchar_t wc_buffer[100];
wsprintfW(wc_buffer, L"%s", pw);
wprintf(L"0x%x\n",wc_buffer[0]);
wprintf(L"c:%c\n",wc_buffer[0]);
return 0;
}
参考:
http://blog.csdn.net/luoweifu/article/details/49382969
《Windows程序设计 第5版 珍藏版》 (美) Charles Petzold著