有关Unicode与多字节字符集的介绍这里不再赘述,摘抄一段话(忘记出处了),说明一下为什么我们需要Unicode。
我们可以在一台机器上阅读多个国家不同语言的文档了,前提是本机必须安装该文档使用的字符集。
操作系统在发布的时候,通常会往机器里预装标准的字符集还有平台专用的字符集,这样只要你的文档是使用标准字符集编写的,通用性就比较高了。
虽然通过使用不同字符集,我们可以在一台机器上查阅不同语言的文档,但是我们仍然无法解决一个问题:在一份文档中显示所有字符。为了解决这个问题,我们需要一个全人类达成共识的巨大的字符集,这就是Unicode字符集。
Unicode和多字节主要是针对字符串说的。对于Unicode,所有字符都是2个字节来表示,而多字节,英文字符1个字节,汉字2个字节。
《Windows核心编程》中对为什么使用Unicode做了一些论述,摘抄如下:
- Unicode使程序的本地化变得更容易。
- 使用Unicode,只需发布一个二进制(.exe或DLL)文件,即可支持所有语言。
- Unicode提升了应用程序的效率,因为代码执行速度更快,占用内存更少。Windows内部的一切工作都是使用Unicode字符和字符串来进行的。所以,假如你非要传入ANSI字符或字符串,Windows就会*分配内存,并将ANSI字符或字符串转换为等价的Unicode形式。
- 使用Unicode,你的应用程序能轻松调用所有不反对使用(nondeprecated)的Windows函数,因为一些Windows函数提供了只能处理Unicode字符和字符串的版本。
- 使用Unicode,你的代码很容易与COM集成(后者要求使用Unicode字符和字符串)。
- 使用Unicode,你的代码很容易与.NET Framework集成(后者要要求使用Unicode字符和字符串)。
- 使用Unicode,能保证你的代码能够轻松操纵你自己的资源(其中的字符串总是Unicode的)。
自己添加几条:
- Unicode是趋势。从VS2003开始VC方面的项目默认的都是Unicode的工程,VS2013默认不再支持多字节字符编码,如需要用多字节字符集,需要自己另外下载补丁包。
- 某些函数或者库只支持Unicode字符,比如GDI+。
- 与多字节字符工程相比,界面外观不同。
Unicode界面
多字节界面
但是,在实际中,情况却是很多地方都在用多字节字符集,究其原因,在于兼顾历史。试想系统基本基于以前的多字节字符集的底层模块和多字节字符集的开源库,谁有勇气将其改用Unicode字符集一一重新编译呢?即使有勇气,其潜在的不确定风险也实在太大了。而另一方面,软件的多语言版本对于国内大多数软件更像一个有点遥远的梦想,所谓Unicode版本比多字节版本运行得更快,在硬件飞快发展的今天估计只存在于理论之中,这种细微差别用户基本上不会察觉,更提不上构成效率瓶颈。
那么我们该如何做呢?虽不能立刻转用Unicode,但我们可以做好准备,平常写代码时养成一些习惯,让代码的适应性更强。就算以后要切换编码方式,改动工作量也会少很多,甚至完全不需要改动代码。
- 程序中输入字符串时,养成习惯,记得加上_T宏。
_T宏能适配工程的字符集,Unicode环境下为宽字符,多字节环境下为一般的多字节字符。 - 需要使用char时,用TCHAR代替。
TCHAR也是适配的,Unicode环境下为wchar_t,多字节环境下为char。 - 使用CString类。
CString也是适配的,Unicode环境下为CStringW,多字节环境下为CStringA 。 - 某些api函数在Unicode与多字节下有不同的形式,比如fwprintf_s与fprintf_s。必要时使用条件编译指令#ifdef UNICODE,保留函数调用的两种版本,则无论在何种环境下,代码都能通过编译。
例如,打开文件时,
#ifdef UNICODE
_wfopen_s(&pFile, filename, _T("rt"));
#else
fopen_s(&pFile, filename, _T("rt"));
#endif
PS:
_wfopen_s()不是标准C里的函数,只能在windows上用,Linux下没有这个函数。
fopen()你应该很清楚了,就是你传入一个文件名和读写模式,然后它就给你一个FILE*句柄。文件名是char *类型的。
_wfopen_s()跟fopen()有两点区别:
1. _w表示传入的参数是wchar_t *类型的。就是说,你必须传入Unicode字符串。在中文操作系统里,日文,韩文或者泰文等非拉丁语系的文字,如果用普通字符串表示,可能会显示成乱码,这个时候你用fopen()函数就没法打开指定的文件。反之,中文在其他语言的操作系统里也有一样问题,而Unicode就没有这个问题。
2. _s表示该函数是更安全的版本,安全性主要体现在多了溢出检测。