以前也零零散散看过一些字符编码的问题,今天看来这边博客,感觉很多东西都总结在里面,非常值得学习!

一、字符集的历史渊源

在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前的一个点符号)。

参考:http://www.cnblogs.com/fanzhidongyzby/archive/2012/08/28/2660562.html

Windows字符集的统一与转换的更多相关文章

  1. MySQL字符集设置及字符转换(latin1转utf8)

    MySQL字符集设置及字符转换(latin1转utf8) http://blog.chinaunix.net/uid-25266990-id-3344584.html  MySQL字符集设置及字符转换 ...

  2. 查看当前windows字符集

    查看当前windows字符集 命令行输入:chcp

  3. [转]关于Navicat和MYSQL字符集不统一出现的中文乱码问题

    原文链接:关于Navicat和MYSQL字符集不统一出现的中文乱码问题 最近遇到一串关于MYSQL中文乱码的问题,问题背景是这样的: 在此之前,服务器上安装好MySQL之后就立马重新配置了字符集为ut ...

  4. 实现Redhat Linux 6和Windows通过Windows Server AD统一认证并共享访问Oracle ZS存储系统

    Windows Server 2012 AD设置 1.  建立新的组织单位OU 为用户提前建立好OU,是为了AD用户管理简单清晰. 2.  建立新的用户和用户组 建立新的用户的时候,要同时将用户归属到 ...

  5. Windows / VS下不同类型变量转换

    [时间:2016-07] [状态:Open] [关键词:windows,vs,mfc,类型转换] 在实际编码中经常遇到不同类型及编码方式的字符串.变量之间的转换,比如Unicode->char. ...

  6. windows和linux文件的转换

    由于windows与unix系统的换行不一致,因此需要相互之前的格式转换 只需要在linux上执行 dos2unix filename 将windows下的文本文件转换成linux上可以浏览的文件 u ...

  7. Windows使用Python统一设置解析器路径

    碰到的问题: .py文件放在cgi-bin文件夹下面,这个.py文件都要设置"#!python.exe路径"来告诉CGI如何找解析器解析这个.py的文件,我是想知道这个路径可否统一 ...

  8. 使用docker toolbox 在windows上搭建统一环境

    1.先下载docker toolbox 以下是下载地址: http://get.daocloud.io/#install-docker-for-mac-windows 2.下载安装 git windo ...

  9. Oracle客户端与服务器字符集不统一的处理

    当Oracle客户端与服务器的字符集不统一时. 症状: 如:ORA-00283: ?????????? 提示信息中有好多问号. 解决方法: 1查询服务器的字符集: SQL> conn / as ...

随机推荐

  1. Git设置及GitHub的使用

    把github上的help略略翻译一遍.备忘. First : 安装:ubuntu 下,终端输入命令: sudo apt-get install git-core git-gui git-doc Ne ...

  2. php多维数组化一维数组

    一.使用foreach <?php function arr_foreach ($arr) { static $tmp=array(); if (!is_array ($arr)) { retu ...

  3. Mac 版 QQ 可直接访问 iPhone 的相册 ?!

    在QQ的聊天窗口中,点击 发送图片 的按钮,会有两个选择项,其中一个就是 从iPhone相册中选取 ,如图 点击  从iPhone相册中选取 后,iPhone上的QQ会收到一条消息 “请选择要上传的照 ...

  4. centos6.5 中文

    之前在网上查了不少资料,很多网友在网上都说,在shell命令下输入:     # vi  /etc/sysconfig/i18n     然后修改LANG="en_US.UTF-8" ...

  5. Oracle中用一个表的数据更新另一个表的数据

    update tbl1 a   set (a.col1, a.col2) = (select b.col1, b.col2                              from tbl2 ...

  6. POJ 1948 Triangular Pastures【二维01背包】

    题意:给出n条边,用这n条边构成一个三角形,求三角形的最大面积. 先求面积,用海伦公式,s=sqrt(p*(p-a)*(p-b)*(p-c)),其中a,b,c分别为三角形的三条边,p为三角形的半周长, ...

  7. (转载)C语言预处理

    C程序的源代码中可包括各种编译指令,这些指令称为预处理命令.虽然它们实际上不是C语言的一部分,但却扩展了C程序设计的环境.本节将介绍如何应用预处理程序和注释简化程序开发过程,并提高程序的可读性.ANS ...

  8. mysql 数据库常用命令总结

    (1)查看数据库可以支持的存储引擎  命令:show engines;  (2)查看表结构命令:desc table_name:(3)显示表的创建语句     show create table ta ...

  9. Python中字符串的使用

    这篇文章主要介绍python当中用的非常多的一种内置类型——str.它属于python中的Sequnce Type(序列类型).python中一共7种序列类型,分别为str(字符串),unicode( ...

  10. Windows 小技巧: 變更輸入法順序

    Windows XP 中還是有辦法變更輸入法順序的!!只不過,要動用到 Regedit.exe 這個程式. 執行 Regedit.exe至 HKEY_CURRENT_USER\Keyboard Lay ...