由一次诡异的codeblocks中文乱码想到的汉字编码知识

由一次诡异的codeblocks中文乱码想到的汉字编码知识
由一次诡异的codeblocks中文乱码想到的汉字编码知识

由一次诡异的codeblocks中文乱码想到的汉字编码知识

一、问题复现

1.用codeblocks新建一个1.c,里面写入:

#include "stdio.h"

main()

{

printf("中文");

}

保存,编译,可以正常显示。

关闭codeblocks,复制了一份1.c,改叫“1-对照.c”,再打开1.c,发现“中文”两个字变成了乱码(是四个字母,好像是俄文)

2.用codeblocks新建一个2.c,里面写入:

#include "stdio.h"

main()

{

printf("为啥这样的中文可以");

}

保存,编译,可以正常显示。

关闭codeblocks,再打开2.c,发现一切正常。

二、思考

百思不得其解,遂查阅了大量关于汉字编码的文章。用winhex查看“1.c”(用codeblocks再次打开过)和“1-对照.c”(没有用codeblocks再次打开过),发现两个文件内码都一样,而且中文两个字的内码没有错,就是GBK对应的编码“D6D0 CEC4“。于是我吐了。。。

”吐定思痛“,我怀疑是codeblocks的自动检测编码机制工作失误,查看了codeblocks的状态栏,果然是将编码错认成了KOI8-R。为什么2.c没有错认呢?可能是因为那几个字的机内码已经不在KOI8-R的范围内了,所以codeblocks正确的认成了GBK。

实际上,因为默认是Windows-936,所以刚新建文件时,editor界面显示正常,保存时,也是用的ANSI编码(在简体中文win7上就是Windows-936就是GBK)

个人认为,源码是什么编码,gcc就认为是什么编码,生成的exe也就是什么编码,而不是像网上说的

“如果源文件的字符集是GBk,那么就必须指定-finput-charset=GBK,如果不指定,一律当做UTF-8处理。除非你源文件真的是UTF-8,否则就会出现转换错误。”&“并且生成的exe默认是UTF-8的”;否则,我的codeblocksGCC编译器不加-fexec-charset=GBK (还有说让加-finput-charset=UTF-8的)按说就不应该生成能正常显示中文的程序了啊。当然,小弟学识太浅,如果有错,还请高手指正。

三、汉字编码的相关知识

原版资料就不摘了,网上一搜一大把,这里只说说自己的理解。

任何符号都要编码才能在计算机中显示,英文,中文等都不例外。因为西文数量少,编码简单,涉及到的不多,所以设计到的概念较少(至少从网上的资料看,西文的编码没有这么多概念)。然而到了汉字这,情况就不一样了。人们为了编码有条理、方便查找,发明了输入码、交换码、机内码的概念。

输入码简单理解就是用输入法的时候打的符号,不同输入方法,输入码就不同。

交换码是为了方便交换而设定的编码,就是对符号的第一次编号。对于汉字,我们目前常提到的交换码是“区位码”、“国标码”,来自于GB2312-80标准。以下所说的“区位码”特指汉字的区位码,笔者虽然没见过别的文字的区位码,但是想来区位码这个概念也能用在其他文字上。

机内码就是计算机储存空间中存储的二进制形式的编码,人们常写成16进制方便阅读。

//========================================

查表得到的区位码一般是十进制数,由区码、位码构成,是两个两位数,而不是一个四位数,转换成国标码的时候要先转成十六进制区位码。这里要注意,十进制区位码转成十六进制区位码的时候,要分成高位两位和低位两位分开转换,而不是把那个四个数当成一个十进制数整个转成十六进制数!!

例如:“文”,区位码4636,要先分成高位两位46和低位两位36,然后把他们分别转换成十六进制数,即2E24(H)。然后就可以加0x2020得到国标码4E44(H),再加0x8080得到机内码CEC4(H)了。

我一开始总是把4636直接转成121C(H),再+0x2020 +0x8080,然后就悲剧了。

//=========================================

下面有些自己的一些推论,可能会有错,抛砖引玉了

1.理解了交换码、机内码,个人感觉其实交换码、机内码这些概念其实也是适用于英文等西文的,只不

过西文的交换码、机内码是一样的罢了。证据:比如说ASCII=American Standard Codeimformation Interchange,从名字就能看出这是交换码,并且大家都知道,英文存在内存以及硬盘里的时候(机内码),也是ASCII码的形式。

2.Unicode编码系统中“代码点”这个概念就是“交换码”。UCS是“人类符号”到“代码点”的映射

关系,UTF是“代码点”到“机内码”的映射关系。

3.同理,在GB2312中由区位表是“汉字”到“区位码”的映射关系,”十六进制区位码+A0A0(H)=

机内码”是“区位码”到“机内码”的映射关系。

4.GBK是对GB2312的内码进行了拓展(GBK的K就是这个“扩展”的意思),并且只保留高位字节

的第八位置一,不再强制低位字节的第八位置一,这样才扩展了编码空间。

5.区位码是GB2312特有的。GBK是对GB2312内码直接扩展的,而不是对其区位码进行扩展的,所

以GBK新增加的汉字是没有区位码的。也就是说,对于GBK相对于GB2312新增加的汉字,他们是直接由“人类符号”映射到“机内码”的。证据:我找了一张UNICODE,GBK,GB2312对照表,发现里面的区位码一栏很多空白。

6.这个不是什么推论,是猜测:所谓的GBK向上兼容UNICODE,只是说GBK里面的汉字,unicode

里面都有,但是没有简单的对应关系。因为GBK跟unicode里面汉字的顺序是不一样的。四、解决方案

如果只是想解决最开始那个问题只需要:取消codeblocks的auto-detection,即在codeblocks 的editor设置中的encoding处选“as default encoding( bypassing C::B’s auto-detection)”。

相关主题
相关文档
最新文档