Visual C++下的unicode

转自:http://blog.sina.com.cn/s/blog_6fd2ddb4010115xo.html

参考:UNICODE编程入门

            C/C++对Unicode编码的处理

一、什么是Unicode

  先从ASCII说起,ASCII是用来表示英文字符的一种编码规范。每个ASCII字符占用1个字节,因此,ASCII编码可以表示的最大字符数是 255(00H—FFH)。其实,英文字符并没有那么多,一般只用前128个(00H—7FH,最高位为0),其中包括了控制字符、数字、大小写字母和其它一些符号。而最高位为1的另128个字符(80H—FFH)被称为“扩展ASCII”,一般用来存放英文的制表符、部分音标字符等等的一些其它符号。& ?: o: h2 \) @# c$ A) D
  这种字符编码规则显然用来处理英文没有什么问题。但是面对中文、阿拉伯文等复杂的文字,255个字符显然不够用。
于是,各个国家纷纷制定了自己的文字编码规范,其中中文的文字编码规范叫做“GB2312—80”,它是和ASCII兼容的一种编码规范,其实就是利用扩展ASCII没有真正标准化这一点,把一个中文字符用两个扩展ASCII字符来表示,以区分ASCII码部分。# A5 ^& H) v: d1 ?, p
  但是这个方法有问题,最大的问题就是中文的文字编码和扩展ASCII码有重叠。而很多软件利用扩展ASCII码的英文制表符来画表格,这样的软件用到中文系统中,这些表格就会被误认作中文字符,出现乱码。
  另外,由于各国和各地区都有自己的文字编码规则,它们互相冲突,这给各国和各地区交换信息带来了很大的麻烦。' [# a+ h- b! E1 E/ i
要真正解决这个问题,不能从扩展ASCII的角度入手,而必须有一个全新的编码系统,这个系统要可以将中文、法文、德文……等等所有的文字统一起来考虑,为每一个文字都分配一个单独的编码。
于是,Unicode诞生了。* ~4 v' z. e3 k! G l' c
  Unicode也是一种字符编码方法,它占用两个字节(0000H—FFFFH),容纳65536个字符,这完全可以容纳全世界所有语言文字的编码。
在Unicode里,所有的字符被一视同仁,汉字不再使用“两个扩展ASCII”,而是使用“1个Unicode”,也就是说,所有的文字都按一个字符来处理,它们都有一个唯一的Unicode码。
二、使用Unicode编码的好处
  使用Unicode编码可以使您的工程同时支持多种语言,使您的工程国际化。. R, s3 J1 ?2 r0 N+ I& ~3 `; l
  另外,Windows NT是使用Unicode进行开发的,整个系统都是基于Unicode的。如果调用一个API函数并给它传递一个ANSI(ASCII字符集以及由此派生并兼容的字符集,如:GB2312,通常称为ANSI字符集)字符串,那么系统首先要将字符串转换成Unicode,然后将Unicode字符串传递给操作系统。如果希望函数返回ANSI字符串,系统就会首先将Unicode字符串转换成ANSI字符串,然后将结果返回给您的应用程序。进行这些字符串的转换需要占用系统的时间和内存。如果用Unicode来开发应用程序,就能够使您的应用程序更加有效地运行。* m& }, n) j/ ?% I* @1 g! A+ s9 ?

下面例举几个字符的编码以简单演示ANSI和Unicode的区别:
字符 A N 和
ANSI码 41H 4eH cdbaH
Unicode码 0041H 004eH 548cH三、使用C++进行Unicode编程+ ^) |/ Y* a5 R& F( n4 @% E, ?! q
  对宽字符的支持其实是ANSI C标准的一部分,用以支持多字节表示一个字符。宽字符和Unicode并不完全等同,Unicode只是宽字符的一种编码方式。/ `5 s5 b+ A" j9 L( x, E
1、宽字符的定义
  在ANSI中,一个字符(char)的长度为一个字节(Byte)。使用Unicode时,一个字符占据一个字,C++在wchar.h头文件中定义了最基本的宽字符类型wchar_t:
typedef unsigned short wchar_t;从这里我们可以清楚地看到,所谓的宽字符就是无符号短整数。/ V4 \! R t- }, @5 i
2、常量宽字符串( u0 N W1 X. p
  对C++程序员而言,构造字符串常量是一项经常性的工作。那么,如何构造宽字符字符串常量呢?很简单,只要在字符串常量前加上一个大写的L就可以了,比如:
wchar_t *str1=L" Hello";这个L非常重要,只有带上它,编译器才知道你要将字符串存成一个字符一个字。还要注意,在L和字符串之间不能有空格。5 ]" t8 ?) g8 `. ?- C, P0 N
3、宽字符串库函数
为了操作宽字符串,C++专门定义了一套函数,比如求宽字符串长度的函数是
size_t __cdel wchlen(const wchar_t*);  为什么要专门定义这些函数呢?最根本的原因是,ANSI下的字符串都是以’\0’来标识字符串尾的(Unicode字符串以“\0\0”结束),许多字符串函数的正确操作均是以此为基础进行。而我们知道,在宽字符的情况下,一个字符在内存中要占据一个字的空间,这就会使操作ANSI字符的字符串函数无法正确操作。以”Hello”字符串为例,在宽字符下,它的五个字符是:
0x0048 0x0065 0x006c 0x006c 0x006f
在内存中,实际的排列是:3 l+ _, Q5 Z& {
48 00 65 00 6c 00 6c 00 6f 00  于是,ANSI字符串函数,如strlen,在碰到第一个48后的00时,就会认为字符串到尾了,用strlen对宽字符串求长度的结果就永远会是1!0 {9 u8 q4 L* G w
4、用宏实现对ANSI和Unicode通用的编程. l* ~. M8 H4 ]( n4 @8 q1 A% G
  可见,C++有一整套的数据类型和函数实现Unicode编程,也就是说,您完全可以使用C++实现Unicode编程。% ]% D! f' I9 ^' R; @9 Q
如果我们想要我们的程序有两个版本:ANSI版本和Unicode版本。当然,编写两套代码分别实现ANSI版本和Unicode版本完全是行得通的。但是,针对ANSI字符和Unicode字符维护两套代码是非常麻烦的事情。为了减轻编程的负担,C++定义了一系列的宏,帮助您实现对ANSI和 Unicode的通用编程。5 V2 a2 t- Y, h% F1 Q* r* s
  C++宏实现ANSI和Unicode的通用编程的本质是根据”_UNICODE”(注意,有下划线)定义与否,这些宏展开为ANSI或Unicode字符(字符串)。
如下是tchar.h头文件中部分代码摘抄: ; Q q9 c/ S& O% f r
#ifdef _UNICODEtypedef wchar_t TCHAR;#define __T(x) L##x#define _T(x) __T(x)#else#define __T(x) xtypedef char TCHAR;#endif   可见,这些宏根据”_UNICODE” 定义与否,分别展开为ANSI或Unicode字符。 tchar.h头文件中定义的宏可以分为两类: . E6 j( f2 o1 j
A、实现字符和常量字符串定义的宏我们只列出两个最常用的宏:
宏 未定义_UNICODE(ANSI字符) 定义了_UNICODE(Unicode字符)
TCHAR char wchar_t
_T(x) x L##x注意:
   “##”是ANSI C标准的预处理语法,它叫做“粘贴符号”,表示将前面的L添加到宏参数上。也就是说,如果我们写_T(“Hello”),展开后即为L“Hello”
B、实现字符串函数调用的宏
C++为字符串函数也定义了一系列宏,同样,我们只例举几个常用的宏:) a$ e; h% P: @ C+ I8 V0 v
宏 未定义_UNICODE(ANSI字符) 定义了_UNICODE(Unicode字符)
_tcschr strchr wcschr
_tcscmp strcmp wcscmp
_tcslen strlen wcslen四、使用Win32 API进行Unicode编程
Win32 API中定义了一些自己的字符数据类型。这些数据类型的定义在winnt.h头文件中。例如: : ^: Q9 Y( V# }. {5 |( q; V
typedef char CHAR; typedef unsigned short WCHAR; // wc, 16-bit UNICODE character typedef CONST CHAR *LPCSTR, *PCSTR; Win32 API在winnt.h头文件中定义了一些实现字符和常量字符串的宏进行ANSI/Unicode通用编程。同样,只例举几个最常用的:
#ifdef UNICODE typedef WCHAR TCHAR, *PTCHAR;typedef LPWSTR LPTCH, PTCH;typedef LPWSTR PTSTR, LPTSTR;typedef LPCWSTR LPCTSTR;#define __TEXT(quote) L##quote // r_winnt#else // r_winnttypedef char TCHAR, *PTCHAR;typedef LPSTR LPTCH, PTCH;typedef LPSTR PTSTR, LPTSTR;typedef LPCSTR LPCTSTR;#define __TEXT(quote) quote // r_winnt#endif // r_winnt  从以上头文件可以看出,winnt.h根据是否定义了UNICODE(没有下划线),进行条件编译。
   Win32 API也定义了一套字符串函数,它们根据是否定义了“UNICODE”分别展开为ANSI和Unicode字符串函数。如:lstrlen。API的字符串操作函数和C++的操作函数可以实现相同的功能,所以,如果需要的话,建议您尽可能使用C++的字符串函数,没必要去花太多精力再去学习API的这些东西。/ G2 V2 W% l' S) U
  也许您从来没有注意到,Win32 API实际上有两个版本。一个版本接受MBCS字符串,另一个接受Unicode字符串。例如:其实根本没有SetWindowText()这个API函数,相反,有SetWindowTextA()和SetWindowTextW()。后缀A表明这是MBCS函数,后缀W表示这是Unicode版本的函数。这些API函数的头文件在winuser.h中声明,下面例举winuser.h中的SetWindowText()函数的声明部分:
#ifdef UNICODE#define SetWindowText SetWindowTextW#else#define SetWindowText SetWindowTextA#endif // !UNICODE  可见,API函数根据定义UNICODE与否决定指向Unicode版本还是MBCS版本。5 o" h9 h1 K0 c4 K8 S, S" p! R
  细心的读者可能已经注意到了UNICODE和_UNICODE的区别,前者没有下划线,专门用于Windows头文件;后者有一个前缀下划线,专门用于C运行时头文件。换句话说,也就是在ANSI C++语言里面根据_UNICODE(有下划线)定义与否,各宏分别展开为Unicode或ANSI字符,在Windows里面根据UNICODE(无下划线)定义与否,各宏分别展开为Unicode或ANSI字符。
  在后面我们将会看到,实际使用中我们不加严格区分,同时定义_UNICODE和UNICODE,以实现UNICODE版本编程。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值