各C/C++编译器对wchar_t字符和字符串的正确支持程度
传统的C风格的字符串是以字符 '/0 '为结尾的一系列字节的集合,其一个单元为char类型,
可以保存世界上的几百种不同的字符集,包括ASCII、ISO-8859、GBK、BIG-5、SHIFT-JIS、
UTF-8等等。通常这些字符集都是兼容ASCII字符集的。我们可以把这些兼容ASCII字符集统称
为ANSI字符集。正因为各种不同的字符集的存在,所以在实际的使用中会产生各种缺字和乱码
的现象。
Unicode是包含世界上各种语言和符号的编码。
在实际应用中,Unicode以UTF-8和UTF-16、UTF-32这三种形式存在,这三种形式都可以完
美地表示Unicode的各个码位。
例如:中文的 "中 "字,其Unicode码位为U+4E2D,用UTF-8用三个8位的字节来表示为:0xE4
0xB8 0xAD,UTF-16则使用一个16位的整数0x4E2D来表示,UTF-32则使用一个32位的整数
0x00004E2D来表示。(当字符码位大于0xFFFF时,UTF-8要用四个8位的字节来表示,UTF-16需要
使用2个16位整数来表示)
UTF-16与UTF-32相比,UTF-16显得更加简洁。Windows下普遍使用UTF-16,而Linux和其它
Unix类的系统由于历史上的设计原因,则比较倾向于使用UTF-8和UTF-32这两种传输方式。
C/C++标准均已经提供了wchat_t关键字来实现对Unicode的支持,而且wchat_t类型只用于
Unicode编码。在Windows平台下,wchat_t类型是16位的;而在Linux下,wchat_t类型是32位的。
下面以Windows x86平台下为例子,说明wchar_t字符串在内存中的存储形式:
例如下面一个UTF-16字符串:
wchar_t str[]=L "中文 ";
上面是一个UTF-16的字符串,是分别由0x4E2D,0x6587,0x0000所组成的串。因为x86的CPU
是低字节在前的(Little Endian),所以该wchar_t串在内存中的存储为:2D 4E 87 65 00 00。
Unicode在C/C++中就是这么简单的表示用法,在某些的C/C++编译器中,却不能完善支持,
下面就列举各C/C++编译器对wchar_t字符和字符串的支持程度:
(1)Visual C/C++
Visual C/C++的编译器对Unicode的支持是最完美的,Microsoft是Unicode的创造者之一,
也是极力推荐使用Unicode编码的公司。
Visual C/C++除了完美支持wchar_t类型外,Visual C++ 7.0或者更新版本的编译器还可以
接受UTF-8/UTF-16编码格式的源代码文件。
(2)Borland C/C++
Borland C/C++的编译器对Unicode的支持也是完美的,从1994年的Borland C++ 4.5开始,
Borland C/C++的编译器就能正确处理wchar_t字符和字符串。
C++Builder 6.0的编译器还添加了 -CP 参数来支持各种不同Codepage的源代码。
C++Builder 2006还可以支持UTF-8编码格式(带BOM)的源代码文件,但是不支持UTF-16
编码格式的源代码文件。
(3)gcc
GNU C/C++编译器也可以正确支持wchar_t字符和字符串,但是源代码的保存格式必须符合
下面条件:
一、源代码文件的保存编码必须是UTF-8
二、UTF-8编码格式的源代码文件,不能有BOM标志头。
只有源代码文件符合上面两个条件,gcc才会正确支持wchar_t字符和字符串。如果不符合
上面两个条件的话,有可能会编译出错,有可能会产生错误的wchar_t字符和字符串。
gcc在Windows平台下,wchar_t是16位类型,在Linux平台下,wchar_t是32位类型。
另外,GCC提供了以下的参数开关来支持其它文字编码的源文件:
(a)-finput-charset=charset
gcc在默认情况下,总是假设源代码的编码是UTF-8,如果是其它编码的源代码文件,
源代码里面又用到了wchar_t的类型,则可以使用-finput-charset=charset这个参数
来实现。
例如通常使用GBK编码的源代码可以假如参数:-finput-charset=GBK
(b)-fwide-exec-charset=charset
默认情况下,gcc在Windows平台下,宽字符串串常量的每个字符是16位UTF-16类型,
在Linux平台下,宽字符串串常量的每个字符是32位UTF-32类型,
使用这个参数,可以改变宽字符串串常量的类型。
例如在x86的机器环境,Linux操作系统下,要使例如 L"汉字" 编译后保存为UTF-16
的字符串,则可以使用 -fwide-exec-charset=UTF-16LE
(4)Digital Mars C/C++
Digital Mars C/C++ 的前身是Symantec C/C++。
Digital Mars C/C++也可以正确支持wchar_t字符和字符串。
但是Digital Mars C/C++不能接受UTF-8(带BOM)、UTF-16编码格式的源代码文件。
(5)OpenWatcom C/C++
OpenWatcom C/C++不支持wchar_t字符和字符串。
虽然OpenWatcom C/C++在处理wchar_t字符和字符串时,不会编译错误,但是所产生
的wchar_t字符和字符串确实错误的。
OpenWatcom C/C++也不能接受UTF-8(带BOM)、UTF-16编码格式的源代码文件。
OpenWatcom可以说是对Unicode支持最差的编译器。
(6)Intel C/C++
和Visual C++差不多。
是否支持UTF-8/UTF-16编码格式的源代码文件,本人则没有进行详细的测试。
(6)PGI C/C++
没有对这个编译器进行详细的测试,但是PGI C/C++的前端是来自gcc,理论上应该跟
gcc相差不远。