VS下的编码问题 | 轻流扇
0%

VS下的编码问题

编码?在VS下的理解。

preface: 参考文章:VS2019 编码问题,如何完美改为UTF-8_vs utf-8-CSDN博客 | 探究Visual Studio中的乱码问题_visual studio 英文乱码-CSDN博客

引入

关于字符的编码,有ANSI(也可以认为就是GBK,中国汉字用的编码),ASCII(仅支持2^8个字符),utf-8(全球统一编码)。不懂的可自行查阅:锟斤拷烫烫烫�ַ��ͨ?文字乱码频发 你该如何避免?带你探索乱码编码解码的前世今生_哔哩哔哩_bilibili|  

在VS中文版,默认的字符编码格式就是GBK,当我们通过特殊的方法改成通用的utf-8时,却发生了匪夷所思的一幕。、

//文件存储的编码格式是 utf-8。

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
#include <windows.h>

int main() {
// 设置控制台输出编码为 UTF-8
SetConsoleOutputCP(65001);//意思就是按照utf-8的密码表,解密得到输出。

// 输出 UTF-8 编码的字符串
printf("完整汉字\n");
return 0;
}

结果却是匪夷所思的 乱码。为什么会这样?

1
2
3
4
5
6
#include <stdio.h>
int main() {
char m[] = { "加咖啡" };//
printf("%s", m);
return 0;
} //文件编码是 GBK

这样的程序运行的结果竟然是正常的?

正文

VS插件FileEncoding

问题一

VS中的三个字符集概念:

1.源码字符集

即源代码文本文件的字符集,NodePad++、记事本、VS Code这样类似的文本编辑器,可以打开源文件看一下你的字符集(文件编码)。

源代码文本文件是以二进制的形式存在硬盘里的,无论中文英文都一样,当你输入一个汉字后保存关闭,这个汉字就会按照你指定的字符集转换成二进制编码保存下去的,当你在以这个格式打开文件时候,就再按照你指定的字符集把二进制转回来。如果两次使用不同的字符集,也就会出现乱码了。
2.执行字符集

执行字符集决定了这行代码在编译器进行编译的时候,str存储的字节到底是什么,你可能会说源码字符集不是已经决定了这个”我”的二进制表示了么?没错,但是这个执行字符集就是让你在这里对它再解释一次。比如我源码字符集可能是UTF8的,但是我可以通过执行字符集来让最终str存储的是GBK的字节编码。
3.解析字符集

最终要还原显示这些二进制字节编码的时候,就需要用到它。比如通过printf()把前面的str显示到控制台时,这个printf()就会按照解析字符集来解析这些字节编码,找到指定字符显示出来。比如下面的控制台输出编码。

简而言之,对于执行字符集,Visual Studio默认根据系统的Locale来决定执行字符集,一般大家都是Windows中文系统,Locale是中国,那么就是GBK编码。对于解析字符集,如果没有手动更改的话,Visual Studio的标准输入输出(printf,cout)到命令行也是根据系统Locael决定的,也就是GBK。

结论

由此,我们可以知道printf中的汉字,实际上编译的时候用的是GBK方式,所以设定控制台输出为utf-8后 就无法正常显示了。

解决方法,一是添加下面的命令#pragma execution_character_set("utf-8");二是在前面添加u8前缀

1
2
3
4
5
6
7
8
9
10
11
12
13
//#pragma execution_character_set("utf-8")

#include <stdio.h>
#include <windows.h>

int main() {
// 设置控制台输出编码为 UTF-8
SetConsoleOutputCP(65001);

// 输出 UTF-8 编码的字符串
printf(u8"完整汉字\n");
return 0;
}

问题二

char是一个字符,用的是ASCII码,那它为何能够储存中文呢?或者说,按道理在gbk的编码格式下,char根本无法正常使用才对啊。

实际上,gbk和utf-8都兼容 ASCII码,也就是说,假如0在ASCII码中编译为0000,那再gbk中也是0000。所以英文能正常使用。那中文嘞?

我们深刻理解编码、解码原理。加咖啡,占6字节,假设再gbk编码下为000….,那么char的作用,就是储存一个字节而已。然后,系统按照gbk的表,解码,从而正常显示。

所以,当我们把汉字、英文看作 一串二进制的数时,一切便合理起来。

1
2
3
4
5
6
#include <stdio.h>
int main() {
char m[] = { "加咖啡" };//
printf("%s", m);
return 0;
} //文件编码是 GBK

还有,tchar,wchar_t,LPCSTR(long, *p, const, string)。

留下万分之一点,采得孤人所笑言