宽字符,Ansic和Unicode

Posted LT.C#

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了宽字符,Ansic和Unicode相关的知识,希望对你有一定的参考价值。

电脑发展的初期,只是在美国等英文国家使用,英文只有26个字母和其它字符,一个字节最多可以表示256个字符,如字母“A”用0x41(二进制01000001)表示,字母“a”用0x61(二进制01100001)表示。为了使各家电脑公司生产的电脑统一,美国搞了个国家标准ANSI,一直沿用至今,我们今天用的电脑普通情况下使用的都ANSI编码。

ANSI编码,每个字符占一个字节,但最多只能表示256个字符。
汉字等东亚语言字符怎么办呢?于是采用两个字节共同表示一个汉字的方法。二个字节理论上可以表示65535个字符。
因为ANSI标准是用一个字节的7个位表示一个普通字符,最高位为0(如字母“A”的二进制01000001),所以表示汉字就采用最高位为1来表示。如“中”字就是用0xD6、0xD0表示(二进制11010110、11010000)。
程序员判断一个字符是否为汉字,就是通过最高位是否为1来判断的。

但是,中国大陆的汉字表示方法叫GB码(中国国家标准,如GB2312),中国台湾、香港的汉字表示方法叫BIG5码(大五码,台湾一家民营公司提出),还有韩、日等字符,还是造成了计算机文字表示的不统一。
所以,在W98时代,电脑上网、收发邮件等经常出现乱码的现象(就是文字标准不统一造成的)

ANSI编码字符,叫多字节字符

UNICODE编码,每个字符占二个字节。也叫万国码(一种国际标准字符集,为世界上绝大多数已知的字符集定义了唯一的16位数值)

UNICODE编码的数字、字母等,保留原ANSI的8位编码,后面加上八个二进制0。
中国国家标准的UNICODE编码汉字,叫GB18030(与UNICODE相同,2002年开始执行),有27533个汉字。

UNICODE编码字符,叫宽字节字符

从Windows 2000开始,使用UNICODE编码,但为了保持兼容,默认的还是ANSI编码。


上面各位提出了两个函数:
WideCharToMultiByte()  //宽字符转多字节字符 
MultiByteToWideChar()  //多字节字符转宽字符 
就是用于两种字符转换的。

那么程序员如何处理这两种编码方式呢?

你可以使用默认的ANSI编码,也可以使用UNICODE编码
比如在VC60下,默认方式下建立的是ANSI编码的工程(注:编译的exe内部,其资源字符是以UNICODE保存)
建立UNICODE编码工程的方法:
1、为工程添加UNICODE和_UNICODE预处理选项。 
  具体步骤:打开[工程]->[设置…]对话框,在C/C++标签对话框的“预处理程序定义”中去除_MBCS,加上_UNICODE,UNICODE。(注意中间用逗号隔开)。
  在没有定义UNICODE和_UNICODE前,所有函数和类型都默认使用ANSI的版本;在定义了UNICODE和_UNICODE之后,所有的MFC类和Windows API都变成了宽字节版本了。
2、设置程序入口点
  因为MFC应用程序有针对Unicode专用的程序入口点,我们要设置entry point。否则就会出现连接错误。
  设置entry point的方法是:打开[工程]->[设置…]对话框,在Link页的Category:Output类别的Entry Point里填上wWinMainCRTStartup。

程序员的几个编程习惯:
1、用THCAR代替char
2、字符串加_T(""),如_T("你好")
3、用_tcscpy等代替strcpy等
ANSI操作函数以str开头,如strcpy(),strcat(),strlen();
Unicode操作函数以wcs开头,如wcscpy,wcscpy(),wcslen();
ANSI/Unicode互为兼容的操作函数以_tcs开头 _tcscpy(C运行期库);
ANSI/Unicode互为兼容的操作函数以lstr开头 lstrcpy(Windows函数);
考虑ANSI和Unicode的兼容,我们需要使用以_tcs开头或lstr开头的通用字符串操作函数。

这样,你在ANSI/UNICODE环境下编译时,可以不修改代码。


ANSI/UNICODE下的字符转换和其它
1、在ANSI下,如果程序本身产生的字符(串),如在代码中直接赋值的CString str = _T("你好"),不需要转换,但是,字符(串)是从其它地方来的,如读取UNICODE编码的文件,通信接收的UNICODE数据,则需要转换,转换使用上面两个函数。

2、同理,在UNICODE下,如果程序本身产生的字符(串),如在代码中直接赋值的CString str = _T("你好"),不需要转换,但是,字符(串)是从其它地方来的,如读取ANSI编码的文件,通信接收的ANSI数据,则需要转换,转换使用上面两个函数。

3、不管是ANSI,还是UNICODE,在资源中的字符串,如String Table中的、对话框的静态文本,都不需要转换,因为它们编译后是以UNICODE保存在.exe中的。
对话框上的汉字,只要是简繁同形的,同一个.exe运行在简体Windows和繁体Windows下都可以正常显示,当然两者必须要有对应的字体(库),都用System字体是可以的,或者简体Windows下用“宋体”,繁体Windows下用“新細明體”。简体的“中”和繁体的“中”字体相同,是简繁同形,简体的“国”和繁体的“國”字形不同,是简繁异形。

4、另外,同一个字符串在ANSI和UNICODE下计数个数不同。如“123你好”,在ANSI下是7个字符,在UNICODE下是5个字符。使用CString 的.GetLength()时要特别注意。

ANSI与UNICODE编码的体验 

1、你用Windows下的记事本新建立一个文件,输入一段文字,如“123abc你好”,你可以在任何时间双击打开它,可以看懂里面的文字。 
2、再打开该记事本,选“文件->另存为”,在对话框的“编码”中选“Unicode”,保存,你可以在任何时间双击打开它,可以看懂里面的文字。 

第1步建立的是ANSI编码文件,保存的汉字是GB2312/GBK汉字(ANSI编码),每个汉字占2个字节,数字字母是ANSI字符,每个字符占1个字节。 

第2步建立的是UNICODE编码文件,保存的汉字是GB18030汉字(UNICODE编码),每个汉字占2个字节,数字字母是UNICODE字符,每个字符占2个字节。

3、用十六进制编辑器,如UltraEdit,分别打开上面的两个文件,在十六进制下比较,你会发现其中的奥妙,还有,你再比较这两个文件所占的字节数(不等于字符数)。提示:UNICODE文本文件以0xFE、0xFF开头。

以上是关于宽字符,Ansic和Unicode的主要内容,如果未能解决你的问题,请参考以下文章

彻底弄懂UTF-8Unicode宽字符locale

windows 编程 —— 宽字符集 与 Unicode

宽字符集(unicode)操作函数 (转)

我如何保证终端具有 NCURSES 的 Unicode/宽字符支持?

宽字符与Unicode (c语言 汉语字符串长度)

将字符串宏/常量转换为宽字符/Unicode