本文主要解决以下几个问题:

  • 常用的字符编码方式有哪些?
  • Visual Stdio的默认编码方式是什么?vscode的编码方式是什么?gcc/g++编译后显示结果时编码方式是什么?
  • 跨编辑器和编译器导致的中文乱码改怎么解决?
  • 你敢用这段代码:printf("%c%c%c%c%c%c\n",206,210,176,174,196,227);去表白吗?
  • 编译结果为烫烫烫烫烫是怎么回事?系统过热警告?

如果大神们都知道,也请继续看下去。希望能找出本文的一些错误或者给本萌新一些建议。

序言

有的人可能知道,我会玩一些需要转区的游戏。调整windows的地区,再重启电脑后,许多文档的内容都变成了一堆乱码——这就是不同地区的编码方式不同所产生的问题。然而我之前都忽视了这个问题。

2.png

最近开始了解编码的契机,就是我从VS转用vscode的时候,发现以前写的和Github上克隆一些代码在vscode中中文显示乱码,或者显示正常但gcc编译后中文乱码。

1.png

本文最终将会给出这个问题的解决方案。

字符编码方式

先来看看编码的定义(摘自维基百科):

编码是信息 从一种 形式 或 格式 转换为另一种形式的过程

字符编码当然就是针对字符的转换。常用的字符编码方式有ASCII,GBK,ANSI,utf-8。

ASCII

ASCII的全称是American Standard Code for Information Interchange,即美国信息交换标准码。(小白注意缩写的后两位是ii不是LL也不是Ⅱ,会出大丑的。)ASCII码定义了128个字符,用到了7位二进制位。而我们知道,C语言中的char位一个字节,多出来的最高位MSB通常填0,或者作为奇偶校检位。

ASCII码的出现年代较早。后来制定的大多数编码都是向下兼容ASCII码的。

经常用到的ASCII码:

  • A to Z:65 to 90
  • a to z:97 to 122

GBK

GB想必都不会陌生了,而K是扩(充)的拼音首字母。GBK是我国制定的针对中文的字符编码,从GB2312扩充而来。

中国汉字博大精深,GBK的编码方式也比较复杂。要用的时候直接查表即可。下面给出查找GBK编码并进行转化的一个实例。

  1. 首先在网上查到“我”的GBK16进制内码为CED2。
  2. 将CED2拆分,分别求十进制码。
  3. 用windows自带的程序员计算器得出CE[16]=206[10],D2[16]=210[10].
  4. 206,210分别转化为二进制后拼接在一起即为“我”的二进制编码。

ANSI

ANSI准确来说并不能算字符编码,而应该说是一组兼容ASCII码字符编码的集合,包括了GBK。

windows设置的地区不同,ANSI指的编码方式也不同。比如我们的电脑现在的地区为中国大陆,那么此时ANSI=GBK;如果设置为台湾,那么ANSI=Big5。当然,如果设置为日本,其编码就是日本语的编码。这就是玩某些游戏需要转区的原因,不然你的文字显示就是一团乱码。

utf-8

utf-8是国际统一的编码方式,用于应对世界各地的编码太乱的统一方案。对应的字符集为unicode。

utf-8的编码方式有点麻烦,不做介绍。

utf-8可跨语言,具有很强的兼容性。实际上,现在很多程序员都坚持使用的utf-8编码。

各种工具的编码方式

VS的默认编码方式,经过我的测试,为下面的规则:

  • 全英文为utf-8编码
  • 有中文为ANSI(GBK)编码

VS的编译器MSVC对于中文的编码方式为ANSI,所以ANSI编辑的代码运行时不会中文乱码。


vscode的编码方式可以通过首选项—设置—搜索“encoding”进行修改。这时vscode只是相当于一个编辑器,用于读写文件。比如:用vscode编辑的文件为自己通过上面方式设置的编码(写)。而来自外部的文件,如果为该编码方式,就能正确显示;不是该编码,则会出现乱码。

3.png


vscode要编译C语言只能借助插件和外部的编译器。我使用的是GNU套件,clang应该也一样。下面说说gcc编译后显示的编码。

如你所想,gcc显示的编码和你的windows编码同步,毕竟结果就在命令行显示。比如你的windows默认编码方式为GBK,那么结果显示的编码就是GBK编码。你用utf-8编码方式编辑的文件在运行后就会出现中文乱码。

然而,坚持使用utf-8编码仍是一个好的选择。那么,utf-8编码的.c文件怎么用gcc编译而不乱码呢?

解决方案

gcc有一条命令可以控制编译后按哪种编码来显示:-fexec-charset=GBK

在编译命令后面加一条这个命令就可以了:g++ 'a.cpp' -o a -fexec-charset=GBK

但是,如果每次都这样输入,肯定十分麻烦。我们可以把这句命令加进vscode的插件Code Runner的编译命令中去。具体操作方式如下:

  1. 打开Code Runner的setting.json,找到“code-runner.executorMap”
  2. 将C语言的命令修改为:"c": "cd $dir && gcc '$fileName' -o '$fileNameWithoutExt.exe' -Wall -g -O2 -static-libgcc -std=c11 -fexec-charset=GBK && &'$dir$fileNameWithoutExt'",
  3. 将C++的命令修改为:"cpp": "cd $dir && g++ '$fileName' -o '$fileNameWithoutExt.exe' -Wall -g -O2 -static-libgcc -std=c++17 -fexec-charset=GBK && &'$dir$fileNameWithoutExt'",

上面的命令直接整行粘贴就可以了,没有问题。

开始使用GBK编码

printf("%c%c%c%c%c%c\n",206,210,176,174,196,227);

如果你看了上面关于GBK编码的内容,你很快就会发现,这条语句使用了GBK编码。

按照我之前演示的方式的逆操作,就可以知道,打印的结果为:我爱你(♂)

4.JPG

这样是不是格局一下子就大起来了。

这里把每两个数识别为一组,因为%c%c%c%c%c%c是没有断开的,如果在中间断开,就会出问题。

5.JPG

烫烫烫

有一对对联对得好,

1
2
3
4
手持两把锟斤拷, (GBK与UTF-8)
口中疾呼烫烫烫。(VC++)
脚踏千朵屯屯屯, (VC++)
笑看万物锘锘锘。(HTML)

锟斤拷就是GBK与UTF-8转换时的问题。然而现在电脑已经被调教得太好了所以我弄半天都弄不出来。详见锟斤拷_百度百科

而其中的烫烫烫大概就是和我一样的初学者一定遇到过的问题。

在Visual Studio中的Debug模式下,如果声明一个变量,但是没有初始化,微软会给未初始化的内存复制为0xCC。给为初始化的内存赋0xCC是有原因的,0xCC其实是INT3中断指令,所以如果在Debug模式下试图去执行这块未初始化的内存的话就会中断程序。但VS中调试器默认的字符集是MBCS,而在MBCS中0xCCCC正好就是中文中的“烫”,所以显示出来就都是烫……

所以烫烫烫是只有VS或VC会出现的问题。