Win32 - 关于UNICODE编码

本例介绍了微软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开头的)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
 
// 定义缓冲区长度为256个字符
// (注意,这里为什么用"字符"而不是"字节")
#define BUFFER_LEN256
 
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 ;

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值