ANSI编码和Linux下的mbtowc

原文地址:http://blog.sina.com.cn/s/blog_4723adba0100hnb4.html


本文阐述了在linux下使用标准C库函数mbtowc进行多字节和宽字节转化的方法,以及一些诡异的转化错误的产生原因及解决方法。

 

一、ANSI编码简述

“ANSI编码”不同于ANSI(American National Standards Institute,美国国家标准协会)。ANSI编码是个编码族,是各国(或地区)基于US-ASCII扩展而成的一套用连续两个或更多字节表达一个该国(或地区)特有字符的编码。

 

因此,同样的连续两个字节,在中文操作系统、日文操作系统、韩文操作系统和台湾操作系统显示出来的字符不一样。例如0xC5 0xA9这两个连续的字符,在GB2312下是“农”,在BIG5下是“觼”。各操作系统会按照环境变量,读取这两个字节相应的字符库,从而显示正确的字符。换言之,在没有指定编码方式的前提下,多字节编码的文本毫无意义。

 

 

为了消除多字节编码的“同样的数据文件显示为不同的文字”(也就是数据文件的语义依赖于编码方式)的问题,通常将各国的ANSI编码字符统一转换成Unicode编码。Unicode编码用2个字节(UCS16)或4个字节(UCS32)表示1个字符的编码,因此有充足空间把全世界的字符编成不重复的码。

 

例如,

 

“农”的Unicode(Big Endian)是0x519C

 

“觼”的Unicode(Big Endian)是0x89FC

 

二、mbtowc函数的使用

或许有人要说,在linux下有iconv函数,在windows下有MultiByteToWideByte。但对跨平台开发有某种执着的C/C++程序员肯定不喜欢大量的ifdef-endif,而喜欢用标准C库函数——这些函数虽然在Windows下和Linux下的实现可能稍有不同,但参数和功能总是一致的。

 

 

mbtowc就是标准C库里的多字节转宽字符(wchar_t)的函数。可以把ANSI编码转换成Unicode编码。

 

但由于同样的多字节数据在不同ANSI编码下表示不同的字符,因此需要先告诉mbtowc函数究竟目前的ANSI编码是哪一种ANSI编码才行,否则mbtowc就面临究竟该将“0xC5 0xA9”转换成“0x519C”还是“0x89FC”还是其他结果的困境。

 

 

因此,调用mbtowc前通常需要调用setlocale来告诉mbtowc当前的多字节数据应该按照哪种编码方式理解。

 

 

在服务器开发时,如果客户机传送的是ANSI编码,则需要确定是哪一种ANSI编码。

通知程序确定当前的多字节字符到底是什么ANSI编码,使用的方法是在mbtowc前调用setlocale,该函数用于调整当前环境变量——虽然环境变量很多,但一般都是同一转换比较方便。即setlocale(LC_ALL, "编码名")。

 

三、mbtowc的诡异bug的原因及解决方法

有时候,mbtowc函数会出现某种奇怪现象:输入字符串只有简体字和ASCII字符时一切正常,但只要字符串里带有繁体字,就会返回负数(失败)。原因如下。

 

 

对于中文世界的程序,如果不考虑繁体字的话,一般是GB2312;代码为setlocale(LC_ALL, "zh_CN.GB2312")。通常可以写成setlocale(LC_ALL, "zh_CN")。

 

 

如果出现简体繁体混杂的情况,这说明原来的ANSI编码并不是GB2312,而是更大的字符集,例如GB18030。

 

1980年的GB2312收录了 7445 个字符,包括 6763 个汉字和 682 个其它符号。目前手机等设备必须支持GB2312。

 

GBK是微软公司在Windows95开始对GB2312的扩展。由于Windows的普遍使用,被接受为中国国家标准;收录了 21886 个符号,它分为汉字区和图形符号区。汉字区包括 21003 个字符。汉字区编码向下兼容于GB2312——也就是说同样的多字节数据在GB2312和GBK里表示同样的汉字。而且,由于是微软的扩展,在Windows里GBK沿用了GB2312的CP936代码页。

 

2000年的GB18030取代了GBK1.0成为新的国家标准,收录了 27484 个汉字,同时还收录了藏文、蒙文、维吾尔文等主要的少数民族文字。同样向下兼容于GBK和GB2312。现在PC必须支持GB18030,但手机等嵌入式设备没有强制规定,于是目前低端手机大多沿用容量较小的GB2312。

 

 

因此,在PC上开发程序时,如果是中文世界的程序,在mbtowc前使用setlocale(LC_ALL, "zh_CN.GB18030")即可。


参考链接:http://blog.csdn.net/ldanduo/article/details/8203532

 

 

你可能感兴趣的:(C++)