关于编码的理解,一直是只知其意却不知其乱码原因,故此本篇主要讲解编码的基础以及实际乱码场景解析它的意义。
-
关于编码,通俗地理解为是为数据指定一套规则来表示,因为计算机中是二进制存储数据,所以这个规则就是指定二进制数代表哪些具体的符号。
-
关于字符,这里有一点值得注意(也是我之前很容易混淆的):普遍认为英文字母和特殊符号在计算机中占一个字节,而汉字占两个字节。但实际上 ,一个符号在计算机中所占的字节与具体字符编码有关。
-
“字符编号” 是标识某一字符的号码,且在不同的字符集中,某个字符的字符编号不一定相同。
(1)字符集是什么呢?
准确地说是“编号字符集”,多个字符的集合,例如:ASCII、Unicode等。相当于一个仓库,存储着字符表示的唯一号码,有了号码才能定位到某字符。
(2)经常和字符集混淆的就是字符编码,它又是什么呢?
首先,为什么在记忆里字符集和字符编码感觉是一个东西,有个官方原因就是在Unicode没产生时,各国家在制定自己的编码标准时,她俩是一块制定的(在指定时,一种字符集只制定了一种字符编码…),所以字符集名字就代表了字符编码名字。而Unicode产生时就考虑到了扩展性,一种字符集制定了多个字符编码。字符编码就是规定了字符如何转化成二进制字节流的映射规则。
-
常见的字符集类型只列举一部分,着重讲解的是后面的乱码问题。
ASCII,是美国指定的,英语字母和常用字符可以用这个来书写,但其他国家的文字,包括中文是无法表示的。(这里的无法表示指的是ASCII无法将中文全部表示出来,而且一个中文字符占两个字符宽度)
Unicode, 也称为万国码,为每种语言中的每个字符设定了统一并且唯一的二进制编码。
UTF-8, 是unicode的一个编码类型,为了节省空间,0-127号的字符用1个字节来表示,使用和ASCII相同的编码,只有128号及以上的字符才用2个,3个或者4个字节来表示。ps:大部分汉字会占用3个字节并且高字节会以1110开头,后面的两个字节以10开头。
GB2312,中国国家标准简体中文字符集。 汉字,日文等占两个字节。英文字母等其他ASCII中的字符依然占一个字节。因为计算机会根据高字节的最高位是1和0判断是中文字符还是英文字符,若是1,则截取两个字节来解码。若是0,代表该字符为英文字符,直接使用ASCII来解码。
GBK,是GB2312的扩展,完全兼容GB2312.
(3)c是如何处理宽字符的?
“宽字符并不一定是Unicode,Unicode只是宽字符编码的一种实现。”
//一般字符
char ch = 'A';
//一个字节空间
//十六进制值:0x41,转换十进制65,即是ascll码对应的A
char *ptr;
ptr = "Hello!";
//指针变量需要4个字节空间
//字符串在静态内存中需要7个字节(还有一个表示字符串结束的0)
//宽字符 wchar_t 16位宽
wchar_t wch = 'A';
//
那为什么会乱码?
就是当我们用编码方案A将字符编码,但却用编码方案B来对字符解码,就出现了乱码。
但令人崩溃的是,文本的编码解码不一定只有一次,每次使用的编码方式不一定相同。(- -)
还有就是有时在复杂的环境下很难知道解码方式是什么(下面用实际乱码来解释)
实战乱码问题
json文件编码格式是UTF-8
读取此文件内容时,中文产生乱码…
Loadjson函数内部实现:
一开始遇到这个乱码问题,以为是程序读取文件时解码方式有问题。感觉是程序当初设置“使用Unicode字符集” 有关系。但从翻阅了一些资料,了解到VS创建的项目character set并不是说程序中用的中文都是以Unicode字节进行存储的。而是有char和string,为了支持Unicode字符,还有wchar_t和wstring,我们可以认为string是基于char的,而wstring是基于wchar_t的。
而真正的问题在哪里?我们要了解下VS中字符串存储的时候用了什么编码方式?
参考了一些博主的分析,了解到这和本地码表有关,也就是系统的编码方式
char* str = "中文 zhongwen";
Str指向的内存区域中存储的字节到底是默认会查找本地码表,我用的是win10系统,默认码表时gb2312
为了证明这一点可以举个例子:查看内存地址存储的内容
根据GBK编码方式转换可知:
所以使用的是gb码表。
所以对于这个乱码问题,初步断定,是获取Path属性值数据时,是按GB3212码表来查找的,而文件编码是utf-8所以需要将获取的字符进行转换(utf8ToGb)
因为Path类型获取的是CString,所以还要先转换成string类型再转换编码方式。