跨平台的软件开发总会遇到各种各样的问题,尤其是在一个山寨小公司里面,更是无法避免,因为程序最开始就没有考虑跨平台的事情……

废话少说,话说前两天在编译程序的时候遇到一个诡异的问题,如题目所说,GCC 报错说 cannot convert to execution character set ,字面意思应该是有关字符集的问题。借助 Baidu,找到了 FreeBSDChina 的一个帖子,大概的解释是:

C/C++ 中有这样两个编码概念:

  • source character set — 源文件的编码
  • execution character set — 执行环境的编码

还有一些额外的环境变量就是 locale 类的 LC_XXX 在编译的时候,要执行从 source character set 到 execution character set 的转换。这个是由编译器来完成的。locale 是在程序的运行时决定程序的行为。由于 Freebsd 下 GCC 的局限,你要使用 wide characters, 就是 L"xxxx" 这样的,源文件的编码必须为 UTF-8。如果要在 Shell 下正确的看到 std::wcout 输出的文字,则你的 Shell 的 locale 也必须为 UTF-8。另外,如果你使用的是 gnome-terminal, 注意它的显示编码也必须是 UTF-8 如果你采用了 UTF-8 的方式保存文件, "xxx" 这样的字符串在你的程序中就是以 UTF-8 的方式保存的, L"xxx" 这样的字符串在你的程序中就是以 UCS-4 的方式保存的。为了永远摆脱乱码的困扰,我建议大家忍一忍,都使用 UTF-8 的方式保存文件吧。

我忽然想起来,在我的 iOS 工程中,所有的源代码文件都是从原先的 Windows Mobile 工程引入的,自然所有的源文件编码都是 GBK 系列的(至于 GBK、GB2312 以及 GB18030 之间有哪些微妙的关系,我也懒得搞清楚了),而 VMware 里面的 Mac 系统编码是 Unicode,所以可能会出现这个问题。不过为了确认,我又回到自己的 Linux 系统下,在 UTF-8 的终端下编译了一个 GBK 编码的 c 语言文件,结果也可以顺利执行,看来这可能与 GCC 的版本有关。我的 Arch Linux 下的 GCC 是 4.6版本,而 Mac OS X 下的 GCC 似乎还停留在 3.x 版本。

至于字符编码的转换,在 Linux 下的基础工具和函数库都是 iconv,但是 iconv 比较原始,无法自动检测文件的编码,需要显式指定,enca 基于 iconv,但是提供了根据语言自动检测文件编码的功能,并且更加健壮,更适合于脚本批处理。我用下面的命令将所有的源文件编码转换成 UTF-8:

find . -name \*.c -o -name \*.h -o -name \*.cpp | xargs enca -L zh_CN -x UTF-8

至于 Unicode、UTF-8、GB18030、ISO-8859、ASCII等,除了 ASCII,我一个都没有彻底搞明白。罢了罢了,还是期待 Unicode 早点“一统江湖,千秋万载”吧。