专栏首页技术点滴Windows字符集的统一与转换

Windows字符集的统一与转换

Windows字符集的统一与转换

一、字符集的历史渊源

在Windows编程时经常会遇到编码转换的问题,一直以来让刚接触的人摸不着头脑。其实只要弄清Win32程序使用的字符编码方式就清楚了,图1展示了一个Win32控制台项目的属性中的字符集选项。这里有两个不同的字符集:一个是Unicode字符集,另一个就是多字节字符集MBCS(Multi-Byte Character System),即熟知的ANSI字符集。

图1 Visual Studio Win32项目属性

或许有人和我一样对这么一群“凭空出现”的字符集既痛恨又好奇,痛恨的是为什么不使用统一的方式对字符编码,还要在程序中不断的转换。好奇的原因亦是如此,既然躲不过这些东西,我们就探究一下它们的渊源。

伴随着图形界面计算机的出现,字符集就应运而生了。要显示字符信息,就需要将之转换为二进制信息表示——编码。“可悲”的是计算机是美国人发明的,而英语就是26个英文字母和一些常用标点符号的组合,这些字符称为ASCLL字符集。它是使用1个字节的长度进行编码,也就是能表示256个不同的字符,实际上真正用到的可见字符不到128个。

对于欧美国家的语言字符,ASCLL尚能应付自如,可是随着计算机的发展和普及,伴随着中文、日文、韩文等语言的需求,256个字符远远不能表示所有的常用字符了。这时就需要对原本的ASCLL进行改进以表示更多的字符,最简单最实际的做法就是扩展字节。将128作为分水岭,小于128的字符还是使用正常的一个字节的ASCLL进行表示,保证了英文的兼容。把大于128的字符作为一个引导字节,来决定后边字符的编码的长度和内容。通过这种变长的灵活编码方式,使得这种编码支持了几乎常用的所有语言的字符集,例如我们常用的GB2312、GBK、GB18030等等。由于ASCLL起初是ANSI的标准字符集,因此这种变长编码方式称为ANSI的多字节字符集MBCS,也称为为ANSI字符集。

然而好景并不长,由于变长的字符编码一般都是由各个国家自行编码的,因此没有一个统一的标准。尤其是中文的编码,在中国大陆、中国香港、中国台湾的中文编码方式截然不同,这就给信息的共享带来了很大的困难,最明显的是早期港台的网页到大陆打开时在没有编码转换时就无法正常显示。为了解决这个问题,国际Unicode联盟提出了统一的Unicode编码方式。Unicode标准编码方式是使用2个字节编码, 16位编码可以表示65536个字符,即UTF-16,基本上能表示世界上所有语言常用的字符。但是对于非常用字符则不能表示完全,比如中国的汉字千变万化,光康熙字典收录的字就将近五万个。因此就出现UTF-32编码,它能表示65536*65536=4294967296个字符,足够表示世界上所有语言的字符了。另外,为了保持和ASCLL的兼容以及满足部分只能处理单字节的系统的需要,UTF-8的编码方式使用和MBCS的编码相似的方式进行编码,但是它不和任何一个MBCS编码兼容。

由上可见,多种字符集的出现并非人为,而是计算机发展历史的需要。既然无法改变历史,我们只能顺应历史潮流,学习并正常使用这些千变万化的字符集。

二、字符集的统一处理

回到文章开始提到的Windows程序中使用两种编码方式,我们的目的是明确这两种编码方式的使用区别和相互转化的方式。

首先看字符集使用的区别。

如果使用MBCS字符集一般这么写:

定义一个MBCS字符数组:char arr[LEN];或者CHAR arr[LEN];

定义一个MBCS字符指针:char *p;或者LPSTR p;

定义一个MBCS常量字符串指针:const char * cp;或者LPCSTR cp;

定义一个MBCS常量字符串:cp=”Hello World!\n”;

如果使用Unicode字符集一般这么写:

定义一个Unicode字符数组:wchar_t arr[LEN];或者WCHAR arr[LEN];

定义一个Unicode字符指针:wchar_t *p;或者LPWSTR p;

定义一个Unicode常量字符串指针:const wchar_t * cp;或者LPCWSTR cp;

定义一个Unicode常量字符串:cp=L”Hello World!\n”;

一般字符集和串操作离不开。

如果对MBCS字符串连接、复制、比较、求长运算为:strcat、strcpy、strcmp、strlen。

如果对Unicode字符串连接、复制、比较、求长运算为:wcscat、wcscpy、wcscmp、wcslen。

类似的情况还有很多,那么这里就有很大的问题。如果源代码改变一下字符集的类型,那么源代码中所有和字符、串相关的函数、定义、声明都需要修改。不过这点早就被人考虑到了,Windows提供了头文件tchar.h来解决这些字符集通用的问题。它使用一个UNICODE宏来标识当前工程使用的字符集是MBCS还是Unicode。如果使用tchar如何书写上边的代码呢?

对于相应的字符集定义和串操作如下:

定义一个字符数组:TCHAR arr[LEN];

定义一个字符指针:LPTSTR p;

定义一个常量字符串指针:LPCTSTR cp;

定义一个常量字符串:cp=_T(”Hello World!\n”);

连接、复制、比较、求长运算为:_tcscat、_tcscpy、_tcscmp、_tcslen。

这里的TCHAR不是一个新的类型,它是根据UNICODE宏来自动映射为char和wchar_t,相应的LPTSTR、LPCTSTR、_T()宏亦是如此。

将上述的宏定义抽象出来如下:

#ifdef UNICODE typedef wchar_t WACHR,TCHAR; typedef wchar_t *LPWSTR,*LPTSTR; typedef const wchar_t *LPCWSTR,*LPCTSTR; #define _T(x) L ## x #define _tcscat wcscat #define _tcscpy wcscpy #define _tcscmp wcscmp #define _tcslen wcslen #else typedef char CHAR,TCHAR typedef char *LPSTR,*LPTSTR; typedef const char *LPCSTR,*LPCTSTR; #define _T(x) x #define _tcscat strcat #define _tcscpy strcpy #define _tcscmp strcmp #define _tcslen strlen #endif

因此,使用TCHAR代替已有的字符、串定义、操作可以完成字符集处理的统一和通用化。

三、字符集的相互转换

然而事情并不是总是那么绝对,一个工程中很难保证所有的涉及字符集的地方都是使用的相同的字符集。在一个Unicode字符集的项目中使用MBCS的函数调用是常有的事情,例如系统API WinExec是执行一个Windows命令,它的第一个参数LPCSTR lpCmdLine标识了它只接收MBCS的字符串。为了满足这里“意外”的需求,必须来实现字符集间的相互转化。当然,Windows提供了这种转化方式,但是有多种方式:一种是使用系统提供的API WideCharToMultiByte和MultiByteToWideChar,使用API转换参数较多,使用起来并不是很方便,但是转换结果比较稳定;另外C库提供一种简便的转换函数wcstombs和mbstowcs,这两个函数参数简单,使用起来很方便,例如:

WCHAR src[20]=L"wide 字符"; CHAR des[40]; WCHAR des2[20]; setlocale(LC_ALL,""); wcstombs(des,src,20); cout<<des<<endl; mbstowcs(des2,des,40); wcout<<des2<<endl;

这两个函数使用前需要使用setlocale设置本地化信息,否则转换后的字符串会出现中文乱码情况。对于中文Windows操作系统使用setlocale(LC_ALL,"")即可,否则使用命令chcp查看活动代码页。

对于中文操作系统结果为936,调用setlocale(LC_ALL,".936")也可以正常完成转化(注意936前的一个点符号)。

通过以上的介绍,相信大家对Windows的字符集的使用和转换应该有了一个更清晰的了解,若有错误还望不吝指正!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Lisp的本质(The Nature of Lisp)学习思考

    Lisp的本质(The Nature of Lisp)学习思考 作者 Slava Akhmechet 译者 Alec Jang 出处: http://www....

    Florian
  • git使用小结

    git使用小结 很多人可能和我一样,起初对git是一无所知的。我也是因为一次偶然的机会接触到git,并被它强大的功能所蛰伏。git其实就是一种版本控制工具,就像...

    Florian
  • 设计模式学习心得

    设计模式学习心得 《设计模式:可复用面向对象软件的基础》一书以更贴近读者思维的角度描述了GOF的23个设计模式。按照书中介绍的每个设计模式的内容,结合网上搜集的...

    Florian
  • 理解MySql字符集

    常用的编码格式为:ASCII Unicode-8 Unicode-16 Unicode-32 GB2312 等 ,

    用户1175783
  • 字符集问题的初步探讨(二)

    原文发表于itpub技术丛书《Oracle数据库DBA专题技术精粹》,未经许可,严禁转载本文.

    数据和云01
  • 驱动用户增长? 来,客户调查类型了解一下

    顾客调查可以帮助企业在短时间内用最低成本收集大量顾客反馈。这些调查结果可以帮助企业快速简便地满足顾客的反馈和要求,并且可以识别潜在用户以及进行案例研究。

    iCDO互联网数据官
  • 【数据】 大数据在零售业中的五个用例

    随着零售业持续加速扩张,商户们也急于寻找大数据在零售业中的最佳用例。 根据财经网站Kiplinger报道,2017年,光是零售业销售额就有望增长3.5%,电子商...

    陆勤_数据人网
  • 决胜营销:重视客户有效参与

    大数据文摘
  • 基于5个案例描述大数据如何应用在零售业

    根据财经网站Kiplinger报道,2017年,光是零售业销售额就有望增长3.5%,电子商务则持续大幅迈进,预期增幅15%。从日志文档、交易信息,到传感器数据和...

    1480
  • Google:基于容器的服务发现与负载均衡

    曾在Google广告部门任职,负责广告的架构任务,14年回国同年9月创立数人云,主要基于Docker容器技术为企业级客户打造私有的PaaS平台,帮助企业客户解决...

    技术zhai

扫码关注云+社区

领取腾讯云代金券