Win32 - 关于UNICODE编码
来源:互联网 发布:手机淘宝直通车怎么做 编辑:程序博客网 时间:2024/05/29 16:54
本例介绍了微软C语言使用的两种字符集, ASCII(ISO-8859-1)和UNICODE(UTF-16)字符集以及它们的区别。
注意,对字符集缺乏概念的同学, 请仔细阅读本例, 字符集是整个Win32编程基础的重中之重。
从程序中我们可以学习到, 除过早期C语言支持的ASCII编码外, 新的C语言还支持UNICODE编码, 这是一种可以包含国际化文字的编码格式, 是Windows2000之后版本Windows平台统一采用的文字编码格式。
C语言同时支持ASCII编码和UNICODE编码, 所以对应的数据类型也就提供了两个, char类型和wchar_t类型。对应的字符、字符串操作函数也同时提供了两套, 普通的C标准字符串函数库和以w开头的UNICODE版本扩展函数库(注意, 原有以str开头的字符串函数, 其UNICODE版本是以wcs开头的)
1 #include <stdio.h>2 #include <stdlib.h>3 #include <string.h>4 #include <locale.h>5 6 // 定义缓冲区长度为256个字符7 // (注意,这里为什么用"字符"而不是"字节")8 #define BUFFER_LEN2569 10 intmain(intargc,char*argv[])11 {12 //定义一个ASCII字符变量13 charce='A';14 //定义一个UNICODE字符变量15 wchar_twce='A';16 17 // 定义一个ASCII字符串变量,包含一个汉字18 //(由于一个汉字占用2字节(GB10080编码)),19 // 所以一个char类型变量无法存储,需要一个字符串来存储,20 //所以实际上这个“大”字占据了3个字节,两个字节存放字符21 //本身编码,还有一个/0结束符22 charszC[]="大";23 24 // 定义一个UNICODE字符变量,wchar_t变量可以存放一个汉25 //字,注意字符前的大写L,这个符号表示该字符为UNICODE字26 //符集字符27 wchar_twcC=L'大';28 29 //定义ASCII字符集字符串变量30 constcharcszHello[]="Hello";31 32 // 定义UNICODE字符集字符串变量,注意字符串前的大写L,33 //这个符号表示该字符串为UNICODE字符集字符串34 constwchar_tcwszHello[]=L"Hello";35 36 /*********************************************************37 * 学习字符集,一开始要搞清楚不同字符集占据的空间大小。38 * ASCII字符集每个字符占据1字节,使用char表示39 * UNICODE字符集每个字符占据2字节,使用wchar_t(部分40 *版本C语言使用unsignedshort)表示41 *********************************************************/42 43 // 定义ASCII字符集字符串指针44 //(思考一下,pcszHello和cszHello这两个变量定义的区别在45 //哪里,它们各自代表了什么?)46 constchar*pcszHello="大家好";47 48 //定义UNICODE字符集字符串指针49 constwchar_t*pcwszHello=L"大家好";50 51 // 定义BUFFER_LEN长度存放字节的缓冲区52 //(定义的同时初始化缓冲区是一个好习惯)53 charszBuffer[BUFFER_LEN]="";54 55 //定义BUFFER_LEN长度存放UNICODE字符的缓冲区56 wchar_twszBuffer[BUFFER_LEN];57 58 //使用memset函数可以初始化任何数组,包括字符串数组59 memset(wszBuffer,0,sizeof(wszBuffer));60 61 // 在最新的C语言标准中,所有UNICODE字符在显示前需要62 //设置其国家代码(或称为地域信息),这里设置为中国63 // LC_ALL表示设置所有相关项目为中国,包括文字、时间和64 //货币65 _wsetlocale(LC_ALL,L"zhi");66 67 //输出ASCII英文字符68 printf("sizeof%cis%d,codeis:%u",ce,sizeof(ce),(int)ce);69 70 //输出UNICODE英文字符71 wprintf(L"/nsizeof%cis%d,codeis:%u",wce,sizeof(wce),(int)wce);72 73 /*********************************************************74 * 通过上述代码可以发现,对于英文字符,ASCII编码和75 *UNICODE编码的内码相同,但占用空间不同76 *********************************************************/77 78 //输出ASCII中文字符(实际是一个字符串)79 printf("/nsizeof%sis%d,codeis:%u",szC,sizeof(szC),(int)*(unsignedshort*)szC);80 81 //输出UNICODE中文字符82 wprintf(L"/nsizeof%cis%d,codeis:%u",wcC,sizeof(wcC),(int)wcC);83 84 /*********************************************************85 * 通过上述代码可以发现,GB10080编码和UNICODE编码在86 *编码“大”字时,编码值是不同的,但都占据2字节空间87 *********************************************************/88 89 //使用printf函数输出ASCII字符集字符串并输出其占据空间的字节数90 printf("/nsizeof%sis%d",cszHello,sizeof(cszHello));91 92 //使用wprintf函数输出UNICODE字符集字符串并输出其占据空间的字节数93 wprintf(L"/nsizeof%sis%d",cwszHello,sizeof(cwszHello));94 95 /*********************************************************96 *通过上述的练习可以发现:97 * ASCII字符集字符串长度和其占用空间的字节数一致98 *(包括结束符/0,占据1byte)99 * UNICODE字符集字符串长度是其占用空间字节数的2倍100 *(包括结束符/0,占据2byte),这一点和wchar_t类型为2字101 *节一致102 *********************************************************/103 104 //使用strlen函数测量ASCII字符串长度105 printf("/nlengthof%sis%d",pcszHello,strlen(pcszHello));106 107 //使用wcslen函数测量UNICODE字符串长度108 wprintf(L"/nlengthof%sis%d",pcwszHello,wcslen(pcwszHello));109 110 //使用strcpy_s函数复制ASCII字符串(后缀为_s的函数是原函数的"安全版本",111 //改进了可能出现缓冲区溢出问题的漏洞)112 strcpy_s(szBuffer,BUFFER_LEN,cszHello);113 114 //使用strcat_s函数连接ASCII字符串115 strcat_s(szBuffer,BUFFER_LEN,pcszHello);116 printf("/nlengthof%sis%d",szBuffer,strlen(szBuffer));117 118 //使用wcscpy_s函数复制UNICODE字符串119 wcscpy_s(wszBuffer,BUFFER_LEN,cwszHello);120 121 //使用wcscat_s函数连接UNICODE字符串122 wcscat_s(wszBuffer,BUFFER_LEN,pcwszHello);123 wprintf(L"/nlengthof%sis%d",wszBuffer,wcslen(wszBuffer));124 125 wprintf(L"/n");126 system("pause");127 return0;128 }
现在的程序开发中,往往兼顾ANSI和Unicode,在C++中char是支持ANSI的字符串类型,wchar_t是支持Unicode的字符类型。将字节串转换成字符串的函数有mbstowcs(), MultiByteToWideChar(),将字符串装换成字节串的函数有wcstombs(), WideCharToMultiByte()。其中MultiByteToWideChar() 和 WideCharToMultiByte() 是 Windows API 函数, 而wcstombs()和mbstowcs()则是定义在C的函数库<stdlib.h>中。下边是一个使用ANSI字符串和UNICODE字符串的例子。
// ANSI字符串,内容长度 7 字节
char sz[20] = "中文123";
// UNICODE字符串,内容长度 5 个 wchar_t(10 字节)
wchar_t wsz[20] = L"\x4E2D\x6587\x0031\x0032\x0033";
从例子中可以看到,在字符串前面的大写字母L(代表「long」)。这将告诉编译器该字符串按宽字元保存——即每个字符占用2个字节。
测量字符串长度的strlen函数的宽字元版是wcslen(wide-character string length:宽字串长度),并且在STRING.H(其中也说明了strlen)和WCHAR.H中均有说明。strlen函式说明如下:
size_t __cdecl strlen (const char *) ;
其实大家所熟悉带有字串参数的C执行时期程式库函式都有宽字元版。例如,wprintf是printf的宽字元版。在tchar.h中都有说明,在这里不再赘言。
Unicode编码也存在许多的问题,那就是每个字符串都将占两倍的存储空间,而且函数执行的时候函数库要比常规的函数库要大.所以一般在开发中,出两个版本,一个是处理ASCII字符串,一个是处理Unicode的字符串.最好的解决办法是维护既能按ASCII编译又能按Unicode编译的单一原始码档案。
一个方法是Microsoft Visual C++包含的TCHAR.H表头档案。TCHAR.H为需要字串参数的标准执行时期程序库函式提供了一系列的替代名称(例如,_tprintf和_tcslen)。有时这些名称也称为“通用”函式名称,因为它们既可以指向函式的Unicode版也可以指向非Unicode版。
如果定义了名为_UNICODE的识别字,并且程式中包含了TCHAR.H表头档案,那么_tcslen就定义为wcslen:
#define _tcslen wcslen
如果没有定义UNICODE,则_tcslen定义为strlen:
#define _tcslen strlen
如果定义了 _UNICODE识别字,那么TCHAR就是wchar_t:
typedef wchar_t TCHAR ;
否则,TCHAR就是char:
typedef char TCHAR ;