Unicode字符

来源:互联网 发布:淘宝运费险什么时候退 编辑:程序博客网 时间:2024/05/18 01:52

Unicode字符是ASCII字符编码的扩展。在ASCII中,每个字符用7位表示,而Unicode是完全的16位编码字符形式。这样,就使Unicode可以把世界上所有的书写语言都在计算机中用字符的形式表示出来。Unicode影响到了计算机业的方方面面,其中对操作系统和基于其上的编程语言的影响最大。Unicode的出现动摇了ASCII字符在计算机中的支配地位,而Unicode最终取代ASCII是整个计算机界正在努力实现的目标。

   Windows操作系统中,基于NT内核的系统是从底层支持Unicode的,如Windows NTWindows 2000Windows XP等。Windows 98中只有一小部分支持Unicode。从编程语言的角度来看,传统的C语言通过对宽字符集的支持来支持Unicode

   由于在计算机中,每个字符被定义为8位,而Unicode要占16位,所以可以用双字符的字符集(DBCSDouble_Byte Character Set)来解决Unicode的表示问题。同时,又可以保持与ASCII字符集的兼容性。

   Unicode中,每一个字符的宽度不再是8位,而是16位。这就使Unicode在理论上可以表示65 536个不同的字符,完全可以包括世界上常用的任何文字语言符号,也包括数学和货币的符号。ISO 10646-1Unicode代码的范围做了明确的规定,为不同的语言、数学及货币符号限定了所占用的空间。这样,在全球范围内就初步统一了文字符号在计算机中表示的问题。

   C语言中,涉及到的字符都只占一个字节,即Sizeof(char)返回为1。引入Unicode和宽字符的概念后,char数据类型没有改变。

C语言中的宽字符是基于数据类型wchar_t上的,例如:

typedef unsigned short wchar_t;

   从上可以看出,wchar_t数据类型与无符号短整数类型相同,都是16位宽。用下面的语句可以定义一个宽字符的变量:

wchar_t x = ‘A’;

   这个字符所占的字节数不再是1,而是2。另外,还可以用以下的语句定义一个指向宽字符串的指针:

wchar_t *p = L” HELLO, WORLD!”

   其中,在第一个引号前面的大写字母L表示“long”。它将通知编译器该字符串是以宽字符保存的,也就是必须为每个字符准备两个字节的空间,整个字符串要占用的空间是26个字节(包括末尾有一个0所占的2个字节)。如果不怕麻烦,前一个语句可以这样写:

wchar_t x = L‘A’;

   但事实上,这是没有必要的,因为数据类型已经告诉编译器这个字符要占用双字节空间。

   Windows系统中,为了解决同一个源代码既可以按ASCII编译,又可以按Unicode编译的问题,就必须针对不同的环境给出解决方案。头文件TCHAR.H解决了这个问题。下面是其中的定义:

#ifdef UNICODE

#define _ _T(x) L # # x

#else

#define _ _T(x) x

#endif

   这样,只需对字符串加工即可让程序自己判断所处的系统环境,以采用不同的处理编译方式。定义字符串如下:

_ _T(“HELLO,WORLD”);

   另外,在TCHAR.H中还定义了以下两个相同的宏:

#define _T(x) _ _T(x)

#define _TEXT(x) _ _T(x)

   可以根据需要使用哪一个宏,当然用户也可以定义自己的宏,但为了程序的通用性和可读性,不提倡这样做。

宽字符的表示问题解决了,但以往的库函数对宽字符是否支持呢?下面做一个实验,调用函数strlen来显示在前面定义的宽字符串的长度,例如:

int nLength = strlen(p);

   但是,编译器通常会给出如下一条警告消息:

‘function’: incompatible types – from ‘unsigned short *’ to ‘const char *’

   这表明数据类型产生了冲突,原有的库函数对宽字符并不支持。在这种情况下,惟一的办法是将含有字符串参数的函数全部重写。事实上,这件事情已经做到了。与strlen函数相对应并应用于宽字符的函数是wcslen,它在头文件STRING.HWCHAR.H中均有声明。下面就可以用这个函数试一试,例如:

int nLength = wcslen(p);

   编译通过了,运行得到的数据却比较费解,其结果是12,而不是24。原来,在使用宽字符时,字符串的长度是不变化的,变化的是字节的长度。

在存储宽字符时,要用的存储空间是原来的两倍,而且宽字符运行库中的函数比常规的函数要大。出于种种原因的考虑,读者也许认为有必要建立两个版本的程序:一个用于处理ASCII字符串;另一个用于处理Unicode字符串。事实上这是没有必要的,因为Windows的库函数和头文件已经解决了这个问题。

在有关的函数库中,涉及字符串参数的函数都有两个定义:一个用于ASCII;另一个用于Unicode。例如,在USER32.DLL中,有两个关于信息框的函数:MessageBoxAMessageBoxW。这两个函数的功能完全相同,都用于在指定的窗口内显示对话框。不同的只是前者用于ASCII,后者用于Unicode。在头文件WINUSER.H中有这样一段定义:

#ifdef UNICODE

#define MessageBox MessageBoxW

#else

#define MessageBox MessageBoxA

#endif

   这段定义很明确地告诉用户可以使用MessageBox,不管到底调用了哪个函数,程序在运行时会根据系统是否支持Unicode和用户在使用该函数时参数定义是否用到Unicode来判断该调用哪一个函数。也就是说,在USER32.DLL中并不存在一个名为MessageBox的函数,它只是WINUSER.H中给出的一个入口点。在相关的动态链接库中,这样的函数还有很多,因为对宽字符函数的处理基本上都采用了这种方式。

   有关Unicode的内容就介绍到这里,如果读者有兴趣,可以查阅有关专著。Unicode的最大作用莫过于它可以使所写的程序国际化,正如在前面讨论的,Unicode几乎为世界上的每一种文字语言都提供了可用的空间