C编译器实际上本身并不识别和处理UTF-8、GBK等编码,它只认ASCII字符,通过ASCII字符解析代码,至于多字节字符,比如注释、字符串中的中文字符,C编译器根本不管,它只当字节序列看待,反正ASCII字符已经能正确定界了。因此,实际上字符串中的中文字符,就是按照源代码中的字节序列直接存储的。
真正识别字符编码的地方是终端,终端收到标准输出流中的字节序列,然后按设定的字符编码方式(如UTF-8、GBK)解析这些字节序列,解析成一个个字符(此时就是真正的字符了,比如中文字符),然后绘制到界面中。
因此,要使得中文正常显示,就要保证源文件用的字符编码和终端显示用的字符编码是一样的。
类Unix操作系统现在已经基本将各方面的字符编码都统一成了UTF-8,所以基本不会出问题。问题主要在Windows上。
Windows上,终端(cmd和Powershell)的默认编码是GBK(代码页936),因此,一般将源文件编码方式设置为GBK,则中文字符就能在终端中正常显示。但是,GBK毕竟不是全球通行的字符编码,最好还是用UTF-8,那么就必须将终端的编码方式设置为UTF-8。如果是交互式终端,可以通过执行chcp 65001
来,然后./程序.exe
就能看到UTF-8源文件编译来的程序中文正常了。交互式使用终端时,还可以用Git for Windows自带的终端,是默认UTF-8编码的,但是不支持交互式输入。
但是,如果是直接双击执行程序,Windows会使用cmd来显示控制台程序的输出,此时默认代码页是936,字符编码为GBK,那么UTF-8源文件编译来的程序就会乱码。此时可以通过在源代码中加入system("chcp 65001");
(需要stdlib.h
),来通过程序改变代码页。
Visual Studio中,源代码文件的编码格式是UTF-8 with BOM,之所以加BOM是VS为了确定地识别UTF-8。编译时,VS通BOM检测到源文件的编码是UTF-8,会先将源代码转成本地的字符编码GBK(原来的文件不变),然后编译得到GBK的程序。如果把源文件的编码改成UTF-8 without BOM,就不会做这样的转换。同理,UTF-16 LE、UTF-16 BE都有这样的转换机制。
CodeBlocks不会做任何转换。
CLion默认源文件是UTF-8,但是自带输出窗口本地编码GBK。不过有几个地方可以设置编码,如文件的编码、项目的编码、控制台的编码等。注意,普通执行的窗口始终都是用的本地编码GBK,但是调试执行的窗口编码可以设置成UTF-8。