字符编码问题经常烦扰人。为了避免遗忘,这里我把我理解的一些东西记录下来。
源代码的编码:
源代码的编码在编辑的时候就确定了。一般可以通过编辑器设定。比如notepad++能非常容易的设置源码的编码。
不管是动态语言还是编译型的静态语言,我们都需要某个程序来读取我们的源代码。动态语言使用解释器来读取,编译型语言使用编译器。各种“读取源代码的程序”都有默认的输入编码。2.X版本的python解释器默认源代码是asicii编码,3.X默认是UTF8编码。g++默认是不带bom的UTF8。而MSVC根据是否带BOM来判断是UTF8还是GBK。所以如果你的源代码与“解释器/编译器”的默认编码不一致,那么就应该在源代码当中作出标记,让“解释器/编译器”知道你的编码方式。各种“解释器/编译器"的标注方法不一致。比如在python的源代码中加入# -*- coding: utf-8 -*- 。这个标记应该和你的源码编码一致,不应该随便乱写。
运行时的编码:
这个问题只存在于编译型语言中,比如C/C++。当你给编译器输入源代码的时候,编译器也能正确的判断源代码的编码。但是编译器会对源码中的字符串进行处理。比如在msvc中,如果你的源码是带BOM的UTF8,msvc根据BOM判断你的源码是UTF8,所以它能够正确的理解源码。但是它会把字符串转换为GBK编码存放到数据常量区。当程序运行时,读取的是运行时编码,也就是GBK编码。
//源码:UTF8
cout<<"我是中国人"<<endl;
这里尽管"我是中国人“是以UTF8格式提供给编译器的,但是应该理解为cout<< ”我是中国人“... 这里输入的是GBK编码的"我是中国人"。
对于g++或者mingw就没有这个问题,源码和运行时编码统一为utf8格式。
库内部使用的编码
在使用各种库时,库的内部一般都使用一种字符编码进行处理。比如python内部使用的是unicode。QT也是。所以,针对接受参数为字符串的函数等等,就存在转换问题。比如string.split(),print("hello world")等等这样的函数,一般都是按照库内部使用编码来接受参数。同样某些返回字符串的函数也是返回内部编码的字符串。所以各种转换就必不可少了。
比如由于MSVC的运行时的编码是GBK,而QT内部需要unicode,所以不管你的源码是什么格式,QString::fromLocal8bit("我是中国人")是必须的。
python中的str.decode(), str.encode()就是unicode和其他编码(如gbk)之间转换。
综上:字符编码真的很烦人,最好的方式应该是 源码,运行是编码,库内核,都统一使用UTF8,天下就太平了。