关于C++程序的编码问题
作者:网络转载 发布时间:[ 2014/1/17 9:28:58 ] 推荐标签:C++ 程序
2. 源文件应该采用什么编码?
2.1. 编译器对不同源文件编码的支持一样吗?
根据 http://stackoverflow.com/questions/688760/how-to-create-a-utf-8-string-literal-in-visual-c-2008
一文中提供的资料,gcc/vc各版本对C++源文件编码有不同的处理:
gcc (v4.3.2 20081105):
支持UTF-8编码的源文件,UTF-8编码的源文件不能有BOM。
根据 http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33415 ,似乎gcc 4.4.0
开始支持带BOM的UTF-8文件。
vc2003:
支持UTF-8编码的源文件,UTF-8编码的源文件可以有BOM,也可以没有。
vc2005+:
如果源文件使用UTF-8编码的话,必须有BOM。
Note
gcc提供了-finput-charset参数可以指定源文件的字符编码,但由于标准头文件都是ascii编码的,因此如果要引用标准头文件的话,源代码的编码必须兼容ascii。而vc未能找到类似的选项。
2.2. 源文件应该采用什么编码?
很多文章都推荐C/C++代码中只使用ascii字符,如果有非ascii字符可以用xHH或uXXXX表示。注释中建议使用utf-8编码。也可以使用gettext 把非ascii字符串放到单独的语言文件中,而在源代码中只保留ascii字符。
在实践中,由于xHH或uXXXX等方式很不直观,容易出错且不易发现,而未必所有程序都需要支持多语言,因此未必想引入gettext或类似的解决方案。在这样的情况下,大家都习惯在源程序文件中直接写入中文等非ascii字符,这需要选择一种至少能被gcc和vc接受的文件编码。
本来,Unicode是解决多语言问题的好选择,而UTF-8由于与ASCII兼容,也是通用的Unicode编码方式,但从上面的资料中可见,如果用UTF-8的话,gcc(至少是低版本)不允许有BOM,而vc2005 以上要求必须有BOM,因此同一个文件无法在gcc及vc下通过编译,UTF-8似乎不是一个好的选择。但如果使用gcc比较高的版本(4.4.0以上?),使用带BOM的UTF-8编码文件应该也是可行的。
考虑到目前现状,我们一般都在简体中文Windows下工作,源文件中使用GB18030编码似乎是一个比较现实的选择。在vc下可以直接编译,而在gcc下也可以通过增加编译选项-finput-charset=gb18030予以支持。而且根据维基百科中GB18030的词条内容,GB18030 is a superset of ASCII and can represent the wholerange of Unicode code points(GB18030向后兼容ASCII,并且能表示所有的Unicode码点),因此使用GB18030有足够的表达能力,可以表示所有的Unicode字符。使用GB18030的缺点是在非简体中文版本的VC下,由于无法指定源文件的编码,因此有可能无法正确识别此编码的源文件。
3. 应该使用什么程序内码?
正如前面提到的,C++有窄字符(char)和宽字符(wchar_t)的分别,分别有一套相应的类和函数(string/cout/strlen与wstring/wcout/wcslen等)。前者在不同的编译器下有不同的缺省编码(简体中文vc是GB18030,gcc是UTF-8),后者一般都使用Unicode,其中vc下使用UTF-16,gcc缺省使用UTF-32。C++在输出窄字符时会按程序内码原样输出,不会进行编码转换,因此在使用窄字符时要求程序内码与运行环境编码一致,这样才不会出现乱码。由于简体中文版vc的程序内码是GB18030,因此使用窄字符的vc程序只能运行在GB18030环境下。同样,由于gcc缺省使用UTF-8作为程序内码,因此使用窄字符的gcc程序只能运行在UTF-8的终端环境下。(这里说的都是在源代码中直接写中文等非ascii字符的程序。用前面提到的gettext及其它工具,使用窄字符的程序也可以在不同编码的运行环境中正确输出中文)
C++在输出宽字符时会自动转换为运行环境的编码,因此只要正确设置了运行环境编码,同一个程序可以在不同编码的运行环境中正确显示中文。这一点与Java/.Net很象,Java/.Net的字符串类型都使用Unicode,在输入/输出时都需要与当前运行环境的编码进行互转。
一般来说,如果需要支持多语言,有两种比较好的做法:
使用窄字符,但源程序中只使用ascii字符,非ascii字符通过gettext或其它工具放到单独的文件中,由gettext等工具处理编码转换的问题。
在各种编码的运行环境中均能正确输出中文。
程序中不能直接出现非ascii字符,也不能通过uXXXX方式指定非ascii字符,后者也会被编译器转换为非ascii字符并存放在目标文件中。
注释中可以使用ascii兼容的编码,不影响编译器。
有比较多的现成代码可供重用。
使用宽字符。
在各种编码的运行环境中均能正确输出中文。
程序中可以使用非ascii字符。
需要配合前面的源程序文件编码设置,让编译器能正确识别源程序中的非ascii字符。
由于以前使用宽字符的程序比较少,可供重用的代码较少。
Note
如果程序中需要一些固定字符编码的字符串常量,例如固定是GB18030
编码的字符串常量,这些常量应该以xXX的方式存放字符串常量经GB18030编码后的内容,这样的内容才不会被转换为程序的内码,也不会转换为运行环境编码。
4. 运行环境应该用什么字符编码?
正如上面提到的,使用窄字符和使用宽字符的程序对运行环境的字符编码要求是不一样的。
使用宽字符,只要在程序中正确设置当前环境的字符编码(一般通过locale::global(locale("")) 进行设置),C++标准库会在输入、输出时正确进行字符编码转换,因此可以适应各种编码的运行环境。
使用窄字符,但程序中不出现非ascii字符的话,对运行环境没有特别要求,可以适应各种编码的运行环境。
使用窄字符,程序中也直接使用汉字等非ascii字符的话,由于C++标准库会把目标文件中保存的字符串(以程序内码保存)直接输出,不会进行字符编码转换,因此要求运行环境的编码与程序内码一致。即简体中文VC编译的程序只能运行在GB18030环境下,gcc编译的程序只能运行在UTF-8环境下(可以在编译时通过-fexec-charset参数进行修改)。
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11