您的位置:首页 > 其它

ANSI、MBCS、UNICODE字符集

2014-01-15 18:31 337 查看
1.三种计算机字符集
计算机字符集可归类为三种,单字节字符集(SBCS)、多字节字符集(MBCS)和宽字符集(即Unicode字符集)。

单字节字符集(SBCS)
单字节字符集,称之为SBCS,它的所有字符都只有一个字节的长度。常见字符集有:ASCII码和扩展ASCII码。SBCS字符串由一个零字节结尾,数据类型是char。

ASCII码:
计算机发明后,为了在计算机中表示字符,人们制定了一种编码,叫ASCII码。
ASCII码由一个字节中的7位(bit)表示,最高位空着,范围是0x00
- 0x7F 共128个字符。他们以为这128个数字就足够表示abcd...ABCD...1234...这些字符了。

扩展ASCII码:
咳...说英语的人就是“笨”!后来他们突然发现,如果需要按照表格方式打印这些字符的时候,缺少了“制表符”。于是又扩展了ASCII的定义,使用一个字节的全部8位(bit)来表示字符了,这就叫扩展ASCII码。范围是0x00-0xFF共256个字符。

多字节字符集(MBCS)
咳...说中文的人就是聪明!中国人利用连续2个扩展ASCII码的扩展区域(0xA0以后)来表示一个汉字,该方法的标准叫GB-2312(国标),之后又扩展出GBK和GB18030。后来,日文、韩文、阿拉伯文、台湾繁体...都使用类似的方法扩展了本地字符集的定义, 现在统一称为 MBCS字符集(多字节字符集,既用多个字节表示一个字符)。其实最常见的还是用2个字节表示一个字符,称为DBCS(双字节字符集)。此类常见字符集有gb2312(中国),big5(中国台湾地区),jis(日本)...。多字节字符集(MBCS)兼容单字节字符集(SBCS),通常并不区分他们。同SBCS一样,MBCS字符串也由一个零字节结尾,数据类型也是char。
但这个方法是有缺陷的,因为各个国家地区各自定义的字符集免不了会有交集。因此使用GB-2312的软件,就不能在BIG-5的环境下运行(显示乱码)。

宽字符集(Unicode字符集):
咳...说英语的人终于变“聪明”一些了。为了把全世界所有的文字符号都统一进行编码,于是制定了UNICODE字符集。标准的UNICODE字符集(即UCS-2,又称UTF-16)规定使用2个字节表示一个字符,这下终于好啦,全世界任何一个地区的软件,可以不用修改地就能在另一个地区运行了。Unicode字符数据类型有:WCHAR、_wchar_t、OLECHAR。
举个例子,假如你编写了一个Unicode的软件,它显示一个字符串"中国,崛起!",然后你把这个软件拿到日本去,日本人运行看到的也是"中国,崛起!",只不过他不一定看的懂(不认识中文),但至少不会像MBCS字符集那样是乱码。
但是,标准的UTF-16并不兼容ASCII编码(在基于ascii的编码方案中,一个8位的0x0总是表示一个字符串的结束的,而UTF-16则不然,它的一个字符完全有可能在高8位或者低8位上等于0x0,这会导致很多应用程序错误,尤其是在网络传输协议当中可能导致大量的字符串错误截断)。
为了兼容ASCII编码并方便数据的传输,后来又提出了UTF-8新方案,UTF-8用1到6位(注意不是字节)的变长字节(究竟多少字节不确定)表示一个字符,并且变长字节也最大限度节约了数据占用的字节数。再后来扩展方案UTF-32也提出来了,它用4个字节表示一个字符(这个用的少不管了)。

通常开发环境默认的就使用多字节字符集(MBCS)之一,比如我们中国的默认就使用GB2312字符集,毕竟它是本地字符集,比Unicode字符集(外来的和尚)更常用。Unicode常用于COM和Windows
NT内。又因为ASCII字符集被兼容,可以认为在我们的程序中不是使用的MBCS字符集就是Unicode。

2.字符集的构成:Charset + Encoding
字符集包括两部分:字符的集合(Charset)和编码方案(Encoding)。字符的集(Charset)定义了该字符集内所有的字符本身;编码方案(Encoding)定义了在计算机上表示这些字符的规范(每个字符占几个字节等等问题)。
通常当我们提到GB2312时,是说字符集合是GB2312的,编码方案也是GB2312的,简单的情况的确如此,字符集等于编码,编码等于字符集。但Unicode是个例外,因为虽然Unicode的字符集合只有一个:Unicode字符集(Charset),但是编码方案它有多个:UTF-8,UTF-16(标准方案),UTF-32都是。因此,我们必须明确一个概念,UTF-8是 unicode字符集的一个编码方案,当我们在说到UTF-8字符和Unicode字符的时候,在某些情况下,它们在逻辑上是等价的,但是,他们并不是同一个东西,因为Unicode字符在二进制上还有一个选择就是原生的UTF-16编码。

3.代码页
然后,需要解释一下Codepage-代码页,百度百科上说代码页是字符集编码的别名。你在安装比如Window操作系统的时候若干代码也会随之安装到电脑上,比如codepage936代码页是简体中文,codepage950代码页是繁体中文,codepage932代码页是日文...,对于我们来说codepage936简体中文代码页就是电脑上默认使用的。
再具体说codepage实际是一个从unicode到其他mbcs的转换索引表,我们知道,windows操作系统是完全基于unicode的,正是通过代码页应用程序可以在unicode和本地字符集(如gb2312)之间来回转换。
举个例子,如果我们写了下面的程序:
#include <windows.h>
#include <stdio.h>

int main( void )
{
  SetConsoleOutputCP(936); //指定程序使用的代码页,我们中国默认使用936
  printf("简体中文\n");
  return 0;
}
程序运行结果显示正常:简体中文;
如果我们将main内的第一行的936改成其他的比如437(美国英语),那么将会显示乱码。
原因是程序在编译链接后生成的exe文件内全是01二进制数据,而这些二进制数据正是按Unicode编码方式保存下来的。就是说当编译器看到"简体中文"这个字符串,它会将这4个字符按程序当前使用的代码页(默认936,可在程序中指定其他的)映射成一串Unicode码01110...之类的保存到exe内。然后当我们运行exe时,Windows系统再将exe内的那串Unicode根据操作系统默认的代码页(也是936)再从Unicode映射回本地字符集。

4.程序中使用各种字符集
const char * p = "Hello"; // 使用 ASCII 字符集
const char * p = "你好"; // 使用 MBCS 字符集,由于 MBCS 完全兼容 ASCII,多数情况下,我们并不严格区分他们
LPCSTR p = "Hello,你好"; // 意义同上

const WCHAR * p = L"Hello,你好"; // 使用 UNICODE 字符集(L用来定义UNICODE字符串,L就是转换成宽字符)
LPCOLESTR p = L"Hello,你好"; // 意义同上

const TCHAR * p = _T("Hello,你好"); // 如果预定义了_UNICODE,则表示使用UNICODE字符集;如果定义了_MBCS,则表示使用
LPCTSTR p = _T("Hello,你好"); // 意义同上

  在上面的例子中,T是非常有意思的一个符号(TCHAR、LPCTSTR、LPTSTR、_T()、TEXT()、_TEXT()...),它表示使用一种中间类型,既不明确表示使用 MBCS,也不明确表示使用 UNICODE。那到底使用哪种字符集那?嘿嘿...编译的时候决定吧。设置条件编译的方式是:VC6中,"Project\Settings...\C/C++卡片 Preprocessor
definitions" 中添加或修改_MBCS、_UNICODE。为了程序的可移植性,建议使用T类型!

说明:
1. .NET 的平台CLR (Common Language RunTime库中用定义(#define)
_UNICODE 来表示使用Unicode,在Win32 API中是用定义(#define) UNICODE 来表示使用 Unicode。而大多数应用程序(Application)都是既使用CLR又使用Win32
API,再如宏_T根据_UNICODE定义与否来区分,而宏TEXT则根据UNICODE区分。 所以一般地,_UNICODE和UNICODE 应该在工程设置中同时定义或同时不定义。
2. 关于BSTR的使用:http://www.vckbase.com/document/viewdoc/?id=1911
参考:
http://hi.baidu.com/atgc123/blog/item/0e394e1fe3e7c1fe19d57667.html
http://hi.baidu.com/windtrace/blog/item/fe4879ec73a42dde2f2e21fc.html
http://ltzmage.blog.163.com/blog/static/1796999820100144179987/
http://blog.163.com/xu_chao2000/blog/static/27770610200802005230435/
http://zhidao.baidu.com/question/247158007.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: