11:59 AM
C语言处理中文字符
大部分C语言教材对中文字符的处理讳莫如深,甚至只字不提,导致很多初学者认为C语言只能处理英文,而不支持中文。其实C语言是一门全球化的编程语言,它支持世界上任何一个国家的语言文化,包括中文、日语、韩语等。

中文字符的存储

正确地存储中文字符需要解决两个问题。

1) 足够长的数据类型

char 只能处理 ASCII 编码中的英文字符,是因为 char 类型太短,只有一个字节,容纳不下我大中华几万个汉字,要想处理中文字符,必须得使用更长的数据类型。

一个字符在存储之前会转换成它在字符集中的编号,而这样的编号是一个整数,所以我们可以用整数类型来存储一个字符,比如 unsigned short、unsigned int、unsigned long 等。

2) 选择包含中文的字符集

C语言规定,对于汉语、日语、韩语等 ASCII 编码之外的单个字符,也就是专门的字符类型,要使用宽字符的编码方式。常见的宽字符编码有 UTF-16 和 UTF-32,它们都是基于 Unicode 字符集的,能够支持全球的语言文化。

在真正实现时,微软编译器(内嵌于 Visual Studio 或者 Visual C++ 中)采用 UTF-16 编码,使用 2 个字节存储一个字符,用 unsigned short 类型就可以容纳。GCC、LLVM/Clang(内嵌于 Xcode 中)采用 UTF-32 编码,使用 4 个字节存储字符,用 unsigned int 类型就可以容纳。
对于编号较小的字符,UTF-16 采用两个字节存储;对于编号较大的字符,UTF-16 使用四个字节存储。但是,全球常用的字符也就几万个,使用两个字节存储足以,只有极其罕见,或者非常古老的字符才会用到四个字节。

微软编译器使用两个字节来存储 UTF-16 编码的字符,虽然不能囊括所有的 Unicode 字符,但是也足以容纳全球的常见字符了,基本满足了软件开发的需求。使用两个字节存储的另外一个好处是可以节省内存,而使用四个字节会浪费 50% 以上的内存。
你看,不同的编译器可以使用不同的整数类型。如果我们的代码使用 unsigned int 来存储宽字符,那么在微软编译器下就是一种浪费;如果我们的代码使用 unsigned short 来存储宽字符,那么在 GCC、LLVM/Clang 下就不够。

为了解决这个问题,C语言推出了一种新的类型,叫做 wchar_t。w 是 wide 的首字母,t 是 type 的首字符,wchar_t 的意思就是宽字符类型。wchar_t 的长度由编译器决定:
  • 在微软编译器下,它的长度是 2,等价于 unsigned short;
  • 在GCC、LLVM/Clang 下,它的长度是 4,等价于 unsigned int。
wchar_t 其实是用 typedef 关键字定义的一个别名,我们会在《C语言typedef:给类型起一个别名》一节中深入讲解,大家暂时只需要记住,wchar_t 在不同的编译器下长度不一样。
wchar_t 类型位于 <wchar.h> 头文件中,它使得代码在具有良好移植性的同时,也节省了不少内存,以后我们就用它来存储宽字符。

上节我们讲到,单独的字符由单引号' '包围,例如'B''@''9'等;但是,这样的字符只能使用 ASCII 编码,要想使用宽字符的编码方式,就得加上L前缀,例如L'A'L'9'L'中'L'国'L'。'。

注意,加上L前缀后,所有的字符都将成为宽字符,占用 2 个字节或者 4 个字节的内存,包括 ASCII 中的英文字符。

下面的例子演示了如何存储宽字符(注意引入 <wchar.h> 头文件):

 
  1. wchar_t a = L'A'; //英文字符(基本拉丁字符)
  2. wchar_t b = L'9'; //英文数字(阿拉伯数字)
  3. wchar_t c = L'中'; //中文汉字
  4. wchar_t d = L'国'; //中文汉字
  5. wchar_t e = L'。'; //中文标点
  6. wchar_t f = L'ヅ'; //日文片假名
  7. wchar_t g = L'♥'; //特殊符号
  8. wchar_t h = L'༄'; //藏文
在以后的编程中,我们将不加L前缀的字符称为窄字符,将加上L前缀的字符称为宽字符。窄字符使用 ASCII 编码,宽字符使用 UTF-16 或者 UTF-32 编码。

宽字符的输出

putchar、printf 只能输出不加L前缀的窄字符,对加了L前缀的宽字符无能为力,我们必须使用 <wchar.h> 头文件中的宽字符输出函数,它们分别是 putwchar 和 wprintf:
  • putwchar 函数专门用来输出一个宽字符,它和 putchar 的用法类似;
  • wprintf 是通用的、格式化的宽字符输出函数,它除了可以输出单个宽字符,还可以输出宽字符串(稍后讲解)。宽字符对应的格式控制符为%lc

另外,在输出宽字符之前还要使用 setlocale 函数进行本地化设置,告诉程序如何才能正确地处理各个国家的语言文化。由于大家基础还不够,关于本地化设置的内容我们不再展开讲解,请大家先记住这种写法。

如果希望设置为中文简体环境,在 Windows 下请写作:

setlocale(LC_ALL, "zh-CN");

在 Linux 和 Mac OS 下请写作:

setlocale(LC_ALL, "zh_CN");

setlocale 函数位于 <locale.h> 头文件中,我们必须引入它。

下面的代码完整地演示了宽字符的输出:

 
  1. #include <wchar.h>
  2. #include <locale.h>
  3.  
  4. int main(){
  5. wchar_t a = L'A'; //英文字符(基本拉丁字符)
  6. wchar_t b = L'9'; //英文数字(阿拉伯数字)
  7. wchar_t c = L'中'; //中文汉字
  8. wchar_t d = L'国'; //中文汉字
  9. wchar_t e = L'。'; //中文标点
  10. wchar_t f = L'ヅ'; //日文片假名
  11. wchar_t g = L'♥'; //特殊符号
  12. wchar_t h = L'༄'; //藏文
  13.  
  14. //将本地环境设置为简体中文
  15. setlocale(LC_ALL, "zh_CN");
  16.  
  17. //使用专门的 putwchar 输出宽字符
  18. putwchar(a); putwchar(b); putwchar(c); putwchar(d);
  19. putwchar(e); putwchar(f); putwchar(g); putwchar(h);
  20. putwchar(L'\n'); //只能使用宽字符
  21.  
  22. //使用通用的 wprintf 输出宽字符
  23. wprintf(
  24. L"Wide chars: %lc %lc %lc %lc %lc %lc %lc %lc\n", //必须使用宽字符串
  25. a, b, c, d, e, f, g, h
  26. );
  27.  
  28.  
  29. return 0;
  30. }
运行结果:
A9中国。ヅ♥༄
Wide chars: A 9 中 国 。 ヅ ♥ ༄

宽字符串

给字符串加上L前缀就变成了宽字符串,它包含的每个字符都是宽字符,一律采用 UTF-16 或者 UTF-32 编码。输出宽字符串可以使用 <wchar.h> 头文件中的 wprintf 函数,对应的格式控制符是%ls

下面的代码演示了如何使用宽字符串:

 
  1. #include <wchar.h>
  2. #include <locale.h>
  3.  
  4. int main(){
  5. wchar_t web_url[] = L"http://c.biancheng.net";
  6. wchar_t *web_name = L"C语言中文网";
  7.  
  8. //将本地环境设置为简体中文
  9. setlocale(LC_ALL, "zh_CN");
  10. //使用通用的 wprintf 输出宽字符
  11. wprintf(L"web_url: %ls \nweb_name: %ls\n", web_url, web_name);
  12.  
  13. return 0;
  14. }

运行结果:
web_url: http://c.biancheng.net
web_name: C语言中文网

其实,不加L前缀的窄字符串也可以处理中文,它和加上了L前缀的宽字符串有什么区别呢?我们将在下节《C语言到底使用什么编码?谁说C语言使用ASCII码,真是荒谬!》中详细讲解。

From: http://c.biancheng.net/cpp/html/3424.html

Views: 19 | Added by: liangcx126 | Rating: 0.0/0
Total comments: 0
avatar