探究Visual Studio中的乱码问题

关于乱码,没遇到皆大欢喜,遇到了头痛不已。在Visual Studio中程序遇到乱码,需要明确三个概念,那么问题就好解决了。

三个字符集概念

源码字符集

MSVC中/source-charset

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

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

执行字符集

MSVC中 /execution-charset

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

解析字符集

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

Visual Studio中的字符集分析

默认情况下,Visual Studio 会检测字节顺序标记,以确定源文件是否采用编码的 Unicode 格式,例如 UTF-16 或 UTF-8。 如果未找到字节顺序标记,则假定源文件在当前代码页中编码,除非使用 /source-charset/utf-8 选项指定字符集名称或代码页。 Visual Studio 允许将 C++ 源代码保存在任意几个字符编码中。

代码页是一个字符集,可以包括数字、标点符号和其他标志符号。 不同的语言和区域设置可能使用不同的代码页。 例如,ANSI 代码页 1252 适用于英语和大多数欧洲语言;而 OEM 代码页 932 则适用于日本汉字。

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

如何使用UTF-8

为了全过程都能正常显示,不乱码,那应该三个阶段都需要设置为UTF-8。

源字符集和执行字符集设置为 UTF-8

可以使用 /utf-8 选项将源字符集和执行字符集指定为使用 UTF-8 编码的字符集。 它等效于在命令行上指定 /source-charset:utf-8 /execution-charset:utf-8

在 Visual Studio 开发环境中设置此编译器选项

  1. 打开项目“属性页” 对话框。 有关详细信息,请参阅在 Visual Studio 中设置 C++ 编译器和生成属性
  2. 选择“配置属性”>“C/C++”>“命令行”属性页。
  3. 在“附加选项”中,添加 /utf-8 选项以指定首选编码。
  4. 选择“确定”以保存更改 。

解析字符集设置为 UTF-8

SetConsoleCP 函数设置与调用进程关联的控制台所使用的输入代码页。 控制台使用其输入代码页将键盘输入转换为相应的字符值。

BOOL WINAPI SetConsoleCP(
  _In_ UINT wCodePageID
);

在mian()函数中加入以下代码

std::cout << "GetConsloeCP" << GetConsoleCP() << std::endl;
SetConsoleOutputCP(65001);//65001代表UTF-8,参见代码页标识符
std::cout << "GetConsloeCP" << GetConsoleOutputCP() << std::endl;

qDebug() << QTextCodec::codecForLocale()->name();
QTextCodec::setCodecForLocale(QTextCodec::codecForName("utf-8"));//Qt输出
qDebug() << QTextCodec::codecForLocale()->name();

另外,C++11可以指定字符串字面量的执行字符集了,const char* str = u8"我";在字符串前面加u8就可以了。

/source-charset(设置源字符集) | Microsoft Docs

/utf-8(将源字符集和执行字符集设置为 UTF-8) | Microsoft Docs

SetConsoleCP 函数 - Windows Console | Microsoft Docs

代码页 | Microsoft Docs

代码页标识符 - Win32 apps | Microsoft Docs

MSVC中C++ UTF8中文编码处理探究

猜你喜欢

转载自blog.csdn.net/no_say_you_know/article/details/126695461