本例介绍了C语言使用的两种字符集, 多字节编码字符集(GBK, UTF-8等)和UNICODE(UCS-2)字符集以及它们的区别。
从程序中我们可以学习到, 除过早期C语言支持的ASCII编码外, 新的C语言还支持多字节编码和UNICODE编码, 后两者都这是一种可以包含国际化文字的编码格式, 而且从Windows2000之后系统内核统一采用UNICODE文字编码格式。
C语言同时支持多字节编码和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_LEN 256 int main(int argc, char* argv[]) { // 定义一个ASCII字符变量 char ce = 'A'; // 定义一个UNICODE字符变量 wchar_t wce = 'A'; // 定义一个ASCII字符串变量, 包含一个汉字 // (由于一个汉字占用2字节(GB10080编码)), // 所以一个char类型变量无法存储, 需要一个字符串来存储, // 所以实际上这个“大”字占据了3个字节, 两个字节存放字符 // 本身编码, 还有一个/0结束符 char szC[] = "大"; // 定义一个UNICODE字符变量, wchar_t变量可以存放一个汉 // 字, 注意字符前的大写L, 这个符号表示该字符为UNICODE字 // 符集字符 wchar_t wcC = L'大'; // 定义ASCII字符集字符串变量 const char cszHello[] = "Hello"; // 定义UNICODE字符集字符串变量, 注意字符串前的大写L, // 这个符号表示该字符串为UNICODE字符集字符串 const wchar_t cwszHello[] = L"Hello"; /********************************************************* * 学习字符集, 一开始要搞清楚不同字符集占据的空间大小。 * ASCII字符集每个字符占据1字节, 使用char表示 * UNICODE字符集每个字符占据2字节, 使用wchar_t(部分 * 版本C语言使用unsigned short)表示 *********************************************************/ // 定义ASCII字符集字符串指针 // (思考一下, pcszHello和cszHello这两个变量定义的区别在 // 哪里, 它们各自代表了什么?) const char* pcszHello = "大家好"; // 定义UNICODE字符集字符串指针 const wchar_t* pcwszHello = L"大家好"; // 定义BUFFER_LEN长度存放字节的缓冲区 // (定义的同时初始化缓冲区是一个好习惯) char szBuffer[BUFFER_LEN] = ""; // 定义BUFFER_LEN长度存放UNICODE字符的缓冲区 wchar_t wszBuffer[BUFFER_LEN]; // 使用memset函数可以初始化任何数组, 包括字符串数组 memset(wszBuffer, 0, sizeof(wszBuffer)); // 在最新的C语言标准中, 所有UNICODE字符在显示前需要 // 设置其国家代码(或称为地域信息), 这里设置为中国 // LC_ALL表示设置所有相关项目为中国, 包括文字、时间和 // 货币 _wsetlocale(LC_ALL, L"zhi"); // 输出ASCII英文字符 printf("size of %c is %d, code is: %u", ce, sizeof(ce), (int)ce); // 输出UNICODE英文字符 wprintf(L"/nsizeof %c is %d, code is: %u", wce, sizeof(wce), (int)wce); /********************************************************* * 通过上述代码可以发现, 对于英文字符, ASCII编码和 * UNICODE编码的内码相同, 但占用空间不同 *********************************************************/ // 输出ASCII中文字符(实际是一个字符串) printf("/nsize of %s is %d, code is: %u", szC, sizeof(szC), (int)*(unsigned short*)szC); // 输出UNICODE中文字符 wprintf(L"/nsizeof %c is %d, code is: %u", wcC, sizeof(wcC), (int)wcC); /********************************************************* * 通过上述代码可以发现, GB10080编码和UNICODE编码在 * 编码“大”字时, 编码值是不同的, 但都占据2字节空间 *********************************************************/ // 使用printf函数输出ASCII字符集字符串并输出其占据空间的字节数 printf("/nsize of %s is %d", cszHello, sizeof(cszHello)); // 使用wprintf函数输出UNICODE字符集字符串并输出其占据空间的字节数 wprintf(L"/nsize of %s is %d", cwszHello, sizeof(cwszHello)); /********************************************************* * 通过上述的练习可以发现: * ASCII字符集字符串长度和其占用空间的字节数一致 * (包括结束符/0, 占据1 byte) * UNICODE字符集字符串长度是其占用空间字节数的2倍 * (包括结束符/0, 占据2 byte), 这一点和wchar_t类型为2字 * 节一致 *********************************************************/ // 使用strlen函数测量ASCII字符串长度 printf("/nlength of %s is %d", pcszHello, strlen(pcszHello)); // 使用wcslen函数测量UNICODE字符串长度 wprintf(L"/nlength of %s is %d", pcwszHello, wcslen(pcwszHello)); // 使用strcpy_s函数复制ASCII字符串(后缀为_s的函数是原函数的"安全版本", // 改进了可能出现缓冲区溢出问题的漏洞) strcpy_s(szBuffer, BUFFER_LEN, cszHello); // 使用strcat_s函数连接ASCII字符串 strcat_s(szBuffer, BUFFER_LEN, pcszHello); printf("/nlength of %s is %d", szBuffer, strlen(szBuffer)); // 使用wcscpy_s函数复制UNICODE字符串 wcscpy_s(wszBuffer, BUFFER_LEN, cwszHello); // 使用wcscat_s函数连接UNICODE字符串 wcscat_s(wszBuffer, BUFFER_LEN, pcwszHello); wprintf(L"/nlength of %s is %d", wszBuffer, wcslen(wszBuffer)); wprintf(L"/n"); system("pause"); return 0; }