转载自:https://blog.csdn.net/a10929/article/details/78235793
- 源文件字符集:源文件本身也是文本文件,所以源文件字符集是指源文件保存时采用哪种字符集编码。VC++下源文件默认是gbk编码,如果想要更改,可以通过 文件-高级保存选项 修改某个源文件的编码方式,似乎没有什么选项能够设置创建项目时的源文件编码,需要自己一个一个设。
- 编译器字符集:编译器在读取源代码文件时所使用的内部字符集决定了编译器如何把读入的源代码文件字节流进行转换,转换是指从一种字符集编码的字节经过解码再编码到另一种字符集编码的字节。当然编译器内部采用什么字符集不是我们所关心的,是编译器内部的事情。
- 执行字符集:编译器在编译时会将 字符/字符串 常量从上一步编码得到的字节转化为相应的字符集,转化为哪种字符集决定了程序在运行时这些字符串采用了哪种字符集编码,举个例子:
printf("你好"); //程序在执行时 "你好" 这个字符串在内存中保存的是哪种字符集的编码呢?就由这个第3步决定。
- 1
那么,编译器到底会转化为哪种字符集呢?分2种情况:
1. 如果是窄字符/字符串”“(以char为单位),那么不同的编译器可能不一样。以VC++为例,它是由系统代码页决定的,比如在中文windows系统下就采用GBK编码。
2. 如果字符/字符串前有指定编码方式,那没什么好说的了,就采用指定的编码方式,如下:
char* s1 = u8"hello"; //窄字符串,utf-8编码 (C++11)
wchar_t* s2 = L"hello"; //宽字符串,utf-16编码
char16_t* s3 = u"hello"; //宽字符串,utf-16编码 (C++11)
char32_t* s4 = U"hello"; //utf-32编码 (C++11)
//'\x12' : \x后面接2个16进制数字,可表示一个窄字符char,多个\x连起来可表示一个utf-8字符,如"\xE4\xBD\xA0"
//L'\u1234' : \u后面接4个16进制数字,可表示一个utf-16宽字符
//U'\U12345678' : \U后面接8个16进制数字,可表示一个Utf-32
VC++里如果想要强行改变执行字符集,可以加上一句预处理:
//设置执行字符集为utf-8
#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif
- 1
- 2
- 3
- 4
控制台的代码页默认是和系统代码页是一样的,中文windows下就是GBK,所以你用输出流函数(printf,wprintf,cout,wcout等)输出GBK编码的字符串肯定没问题,现在讨论2种情况:
- 输出宽字符串,如果直接输出是会乱码的。这里有一个函数:setlocale(),是用来程序运行时设置当前系统的区域信息。而在所有C++程序启动前,locale的默认设置setlocale(LC_ALL,”C”);会被执行,这个”C”肯定不是能支持中文的这样一个环境,而宽字符串在输出时会根据setlocale()的设置将其转为相应区域代码页的编码,当然就会出错了。所以我们可以手动设置一下locale信息就可以了:
#include <locale.h>
//使用""的话就从当前系统获取代码页,当然也可以设成具体的,比如"chs"
int main()
{
setlocale(LC_CTYPE,"");
wprintf(L"你好"); //这样就不会乱码了
//...
}
- 对于窄字符串来说,是不会作编码转换的,所以如果你输出GBK编码的窄字符串,那是没有问题的,但如果是utf-8编码的窄字符串呢?显然又会乱码,这时只能修改控制台窗口的代码页了:
//经过测试发现没有乱码,但是鼠标点到字上时会变乱,可能需要设置字体
system("chcp 65001");
printf(u8"你好");
以前采用 Qt + MSVC编译器 时,在程序中需要用到中文时,直接将字符串传给QString或一些Qt的函数时,会出现乱码。这是因为:Qt内部采用utf-16编码,当你将字符串传给QString或一些Qt的函数时,Qt会将默认其当作utf-8编码的字符串来转换,之前说过,VC++下执行字符集默认是GBK的,所以就会乱码。解决方法有如下几种:
- 用QTextCodeC或QString转换
QTextCodeC* c = QTextCodec::codecForName("gbk");
QString s = c->toUnicode("你好"); //从gbk转为QString
//或
QString s = QString::fromLocal8Bit("你好"); //从本地系统代码页转为QString
- 如果支持C++11,直接使用utf-8字符串 u8"你好"
- 强行更改执行字符集,方法之前说过
在Qt5之前有这3个函数,可以设置相应的编码问题:
//设置QString对c风格字符串采用哪种编码方式来处理
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
//设置tr("")时对c风格字符串采用哪种编码方式来处理
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
//主要设置QString::from(to)Local8Bit这个函数认为的本地编码方式
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
在Qt5中前2个函数被删除了,因为Qt5中QString等对c字符串默认采用utf-8处理(以前是Latin1),所以只要采用 Qt Creator+MinGW编译器,就没有问题了。因为Qt Creator源文件默认是utf-8编码,MinGW执行字符集就是utf-8编码,所以可以直接这样用,不会乱码了:
QString s = "你好";
qDebug()<<"你好";
QMessageBox::information(nullptr,"标题","你好");
//...
参考:
微软C/C++编译器中管理字符集的新选项
带你玩转Visual Studio
拨开字符编码的迷雾–编译器如何处理文件编码
控制台输出乱码问题
QTextCodec中的setCodecForTr等终于消失了
源码必须是UTF-8,QString需要它