用VC和gcc同时编译unicode编码的c++源程序
经常在C++程序中加入中文注释,但是如果使用不同的编辑器,编码识别或转换不当,会导致非ASCII字符乱码。
考虑到目前绝大多数编辑器都支持unicode编码(UTF-8)的源文件,我觉得一个稳妥的方式是把自己的代码都保存为unicode(UTF-8)。把原来的ACSII编码的文件转换为unicode网上有一些批量转换工具。值得一提的是众多文本编辑器中只发现EditPlus可以做批量转换,其它编辑器如Notepad++都只能一个文件一个文件地转换(知道如何批量操作的朋友请给些提示?)。VS也可以选择保存文件时的编码格式(在高级保存选项中设置)。还有一个要注意的地方是unicode≠UTF-8,在这点上我以前没有注意,(这里的一篇博文说清楚了这两种编码间的异同,主要区别是unicode固定使用四字节编码所有语言,而UTF-8是可变长度的编码,所以并不一样。)
通过试验得知,VC++和Intel的编译器均支持直接编译带有BOM的UTF-8源文件,但是gcc却不支持。事实上gcc和iconv都不支持读取BOM,但是对于没有BOM的UTF-8编码文件却可以编译。因此,对于跨平台的程序,如果想同时使用VC++和gcc来编译有BOM或无BOM的UTF-8源文件都存在兼容问题。(关于BOM (Byte order mark),wikipedia上有所讨论。)
事实上,解决办法并不难,只是这个问题并没有引起所有编译器厂家的足够重视。这篇文章指名了问题所在并给出了几种解决办法。对于UTF-8,BOM是加在文件最开始的三个字节。我们可以把源文件都保存为带有BOM的格式,这样就满足了VC++编译器的要求。当换用gcc编译器时,在编译之前我们需要使用一些脚本工具来检测BOM的存在并删除它,这样gcc就可以顺利处理无BOM的UTF-8源文件了。
最好的办法是
1 | awk '{if(NR==1)sub(/^\xef\xbb\xbf/,"");print}' INFILE > OUTFILE |
,它使用awk命令和正则表达式来检测文件的第一行开头的三个字符,如果是UTF-8特有的标记,则用空字符串取代它们,这样就实现了清除BOM的目标。
另一个办法是使用tail命令只保留第四个字节和其后的字符,命令如下
1 | tail -c +4 UTF8 > UTF8.nobom |
这个方法有一定缺陷,应为只有对于确定是带有BOM的UTF-8文件才能这样做,否则就会失误。我们可以使用
1 | hd -n 3 UTF8 |
来预先查看一下文件的头三个字符,以确认是否为带有BOM的文件。
至此关于UNICODE源文件和BOM的迷惑终于有了一个完满的答案。
gcc 4.4以前不支持UTF-8 BOM,但是这个bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33415 已经被修复,并且随着gcc 4.4.0发布了,因此,现在的gcc已经可以编译带utf-8 bom的文件了。
Thanks Tao! Good to know this!