本例介绍了微软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_LEN256 |
9 | |
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字符串的例子。 测量字符串长度的strlen函数的宽字元版是wcslen(wide-character string length:宽字串长度),并且在STRING.H(其中也说明了strlen)和WCHAR.H中均有说明。strlen函式说明如下: Unicode编码也存在许多的问题,那就是每个字符串都将占两倍的存储空间,而且函数执行的时候函数库要比常规的函数库要大.所以一般在开发中,出两个版本,一个是处理ASCII字符串,一个是处理Unicode的字符串.最好的解决办法是维护既能按ASCII编译又能按Unicode编译的单一原始码档案。
|