windows下控制台应用程序乱码原因探究
我们平时在写C或C++控制台应用程序时,经常能够碰到输出中文变成乱码的情况。我在另一篇经验中介绍了相关解决方案,也谈及了背后的原因,有兴趣的话可以看看。今天我们要研究研究中文乱码的原因,从中文背后的编码看看是什么原因。
工具/原料
QtCreator集成开发环境
Devc++集成开发环境
notepad++
一、如何查看汉字的编码
1、既然我们知道乱码产生的原因是编码与解码的不匹配。我们只有知道了汉字的编码,了解这些编码上的不同,我们才能搞徇柝璎镨清楚不匹配的原因。我们这里分别通过C语言代码的方式,以及一些辅助软件的方式来查看汉字的编码。编码都是采用十六进制数进行显示的。首先,我们来看看C语言的代码:#include <stdio.h>int main(int argc, char *argv[]){ char wz[] = "水杯"; unsigned char *p = (unsigned char *)wz; unsigned i = 0; printf("sizeof(wz) is %d\n", sizeof(wz)); for (; i < sizeof(wz); i++) { printf("byte: %x\n", p[i]); } printf("chinese output :%s\n", wz); return 0;}可以看到输出的汉字“水杯”的编码,至于是哪个编码待会再说。
2、我们再通过notepad++来查看“水杯”的编码。在notepad++中输入“水杯”,然后点击菜单 插件 - Converter - ASCII->HEX。
3、来看看显示的结果是什么。可以看到notepad++显示的结果与我们C语音程序显示的不一样,notepad++是6个字节,C语音程序是4个字节。
二、查找乱码真实原因
1、我们咸犴孜稍先在QtCreator中运行下程序看看。可以看到乱码出现了,显示了三个字“姘存澂”,这显然不是水杯。我们再看看输出的字节编码,是不是和notepad++中是一样的。因为每个汉字占用2个字节,而notepad++和我们的乱码程序明显是6个字节,也就是3个汉字。
2、看看“水杯”二字的相关编码。先来看看notepad++的。可以看到是“UTF8无BOM格式编码”。原来这个6字节的“水杯”编码是UTF8。
3、我们再来看看我们的C语言源文件的编码。可以看到是“以UTF8格式编码”,有无BOM并不会对汉字编码造成影响。所以我们的源文件也是UTF8格式,而且从打印输出的十六进制编码也可以看出来。
4、再来看看问题的根源。可以看到,我们的控制台代码页是 936(ANS/OEM- 简体中文 GBK),并不是UTF8,所以用GBK解码UTF8必然是乱码。
三、解决方案
1、解决方案我已经在“Windows下控制台应用程序乱码解决方案”经验中介绍了。这里再演示下。我用记事本或者notepad++将源代码转换为ANSI编码,然后保存。
2、然后,再QtCreator中点击Yes to all。之后,源代码中的汉字会变为乱码。
3、按下图中的操作进行。然后我们的代码就正常了。
4、运行下看看。乱码问题解决,可以看到我们的“水杯”汉字编码也变为了四个字节。
5、我们可以在notepad++中检验下ANSI编码格式的汉字。与我们的ANSI源代码编译运行的一样。
6、从实验中我们可以看到QtCreator对汉字的编码与源代码的编码是一致的,所以要解决乱码问题需要从源代码着手。
四、Devc++中的编码问题
1、我们知道ANSI编码肯定是没问题的,那么utf8编码的文件在Devc++中是什么样的呢。我们看到源代码是 无BOM的UTF8编码。但是Devc++打开后,源代码中的汉字变成了乱码。
2、我们訇咀喃谆将源代码中的汉字改正过来。然后 保存 。再看看源代码的编码,竟然是ANSI,我们打开前明明是UTF8。Devc++是按照ANSI进行读文件和写文件的。所以我们只要在Dev艘早祓胂c++中编辑代码,那么乱码的问题就不是大问题。不过本身也不是大问题。
五、C语言代码中要注意的部分
1、主要是这句:unsigned char *p = (unsigned char *)wz;代码中的第一个unsigned不能够丢掉,否则会因为溢出的问题,导致单字节被提升为四字节。看看运行结果就知道了。每个打印输出前都加了六个f。