qt中中英文乱码的原因分析以及解决方法 | 您所在的位置:网站首页 › qt中英文切换 › qt中中英文乱码的原因分析以及解决方法 |
在 Qt 4 的时代,解决中文乱码挺麻烦。要考虑用的是什么编译器,具体的可以参考下面这篇文章: http://blog.csdn.net/brave_heart_lxl/article/details/7186631 到了 Qt 5 的年代,这个问题变得简单了些。因为根据 Qt 的文档: http://doc.qt.io/qt-5.6/qstring.html#QString-7 中规定 QString 的 const char* 构造函数是调用 fromUtf8() 构造的。所以要求字符串字面量是 UTF-8 编码的字节。 这里先要解释一下下面两个概念: 源码字符集(the source character set):源码文件是使用何种编码保存的执行字符集(the execution character set):可执行程序内保存的是何种编码(程序执行时内存中字符串编码)源码字符集很容易理解,就是我们源代码的编码。为了我们的代码能够跨平台,源文件要保存为带 BOM 的 utf-8。 执行字符集就麻烦多了。比如我们下面的代码片段: QString str("我是中文"); 1即使这个文件存为 utf-8 格式了,编译成 exe 文件时,编译器也可能对这个字符串常量进行转码,转为别的编码格式。 在 gcc 中,控制这个转码操作的命令行参数是: -fexec-charset=charset 1如果不指定的话默认是 utf-8。所以我们用 gcc 时很少关注这个问题。 Viual Stdio 中就麻烦多了。这里先说 Visual stdio 2015,这个是我现在用的编译环境。VS2015 中如果源代码是 utf-8的,执行字符集默认是本地 Locale 字符集,对于简体中文的 windows 系统来说,这个 本地Locale字符集是 gb18030。所以直接显示汉字会全是乱码。解决这个乱码有三个办法,第一个办法是编译时加入命令行参数,在 Qt 的 pro 文件中可以这样: msvc:QMAKE_CXXFLAGS += -execution-charset:utf-8 1第二个办法是在源文件中加入: #pragma execution_character_set("utf-8") 1更好的办法是源代码写为: QString str(u8"我是中文"); 1当然,这里要求编译器支持 C++11,因此上面的代码在 VS2005、VS2008 上是无法编译通过的。 另外,如果源代码保存为不带 BOM 的 utf-8。那需要告诉 VS2015 我们的编码格式是 utf-8,可以在 pro 文件中加入如下的代码: msvc:QMAKE_CXXFLAGS += -source-charset:utf-8 1另外再说说 VS2005、VS2008 下该如何设置。首先这两个编译器都不支持 C++11,也不支持执行字符集的设置,执行字符集就是默认的本地 Locale 字符集。所以我们的代码只能写为: QString str = QString::fromLocal8Bit("我是中文");一般在Window开发环境里,是GBK编码,在Linux开发环境里,是utf-8编码。 Qt5默认是utf8编码。简单的说,从Qt5开始,源代码就是默认UTF8编码的。 主要是概念要清楚,Qt5要求是执行字符集是utf8,而你要用printf的话,需要本地字符集。如果你使用的是简体中文的windows系统,也是就gb18030。 考虑在你现在源码字符集是utf8,而且又是用的MinGW,所以执行字符集就是utf8(除非你做了其他设置)。,用printf时,你只需要做一个utf8到gb18030的转换即可。 用这个函数QString::fromLocal8Bit("中文")将中文处理下,再输出看看。 在Qt5,建议使用QStringLiteral来输出硬编码的字符串。
qt5.2.1发布后,源码全部是UTF-8编码,但由于微软的问题,VS2010打上补丁VS2010sp1,加入#pragma execution_character_set("utf-8")可以解决中文乱码问题。#pragma execution_character_set("utf-8") QString::Fromlocal8bit("我是中文") 3 qt中乱码的原因分析一个简 单的 Qt 程序
下面这个小程序,估计大家会感到比较亲切。似乎有相当多的中文用户尝试写过这样的代码: #include #include int main(int argc, char **argv) { QApplication app(argc, argv); QString a= "我是汉字"; QLabel label(a); label.show(); return app.exec(); }编码,保存,编译,运行,一切都很顺利,可是结果呢: 多数用户看到 其他用户看到 ÎÒÊǺº×Ö æˆ‘æ˜¯æ±‰å — 出乎意料,界面上中文没显示出来,出现了不认识字符。 于是开始用搜索引擎搜索,开始上论坛发帖或抱怨 最后被告知,下面的语句之一可以解决问题: QTextCodec::setCodecForCStrings(QTextCodec::codecForName("GB2312")); QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));两条指令挨个一试,确实可以解决(多数用户是第一条,其他用户是第二条)。那么,为什么会这样呢? 两种乱码什么时候出现对这个问题,我想大家可能都有话说。在继续之前,我们先列个表,看看两种乱码分别在那种情况下出现: 我们只列举大家最常用的3个编译器(微软VS的中的cl,Mingw中的g++,Linux下的g++),源代码分别采用GBK 和 不带BOM的UTF-8 以及 带BOM的UTF-8 这3中编码进行保存。 源代码的编码 编译器 结果 GBK cl 1 * mingw-g++ 1 * g++ 1 UTF-8(不带BOM) cl 2 mingw-g++ 2 g++ 2 * UTF-8(带BOM) cl 1 mingw-g++ 2 g++ 编译失败 采用3种不同编码保存的源代码文件,分别用3种不同的编译器编译,形成9种组合,除掉一种不能工作的情况,两种乱码出现的情况各占一半。 从中我们也可以看出,乱码和操作系统原本是没有关系的。但我们在 Windows 一般用的GBK,linux一般用的是不带BOM的UTF-8。如果我们只考虑带*的情况,也可以说两种乱码和系统有关。 QString 为什么会乱码呢真的是 QString 乱码了吗?我们可以问问自己,我们抱怨的对象是不是搞错了? 继续之前,先明确几个概念: 明确概念0: "我是汉字" 是C语言中的字符串,它是char型的窄字符串。上面的例子可写为const char * str = "我是汉字"; QString a= str;或 char str[] = "我是汉字"; QString a= str;等 明确概念1: 源文件是有编码的,但是这种纯文本文件却不会记录自己采用的编码这个是问题的根源,不妨做个试验,将前面的源代码保存成GBK编码,用16进制编辑器能看到引号内是ce d2 ca c7 ba ba d7 d6这样8个字节。 现在将该文件拷贝到正体(繁体)中文的Windows中,用记事本打开会什么样子呢? ... QString a= "扂岆犖趼"; QLabel label(a); label.show(); ...那么放到欧美人的Windows系统中,再用记事本打开呢? ... QString a= "ÎÒÊǺº×Ö"; QLabel label(a); label.show(); ...同一个文件,未做任何修改,但其中的8个字节ce d2 ca c7 ba ba d7 d6,对用GBK的大陆人,用BIG5的港澳台同胞,以及用Latin-1的欧洲人看来,看到的却是完全不同的文字。 明确概念2: 如同我们都了解的'A'与'\x41'等价一样。GBK编码下的 const char * str = "我是汉字"等价于 const char * str = "\xce\xd2\xca\xc7\xba\xba\xd7\xd6";当用UTF-8编码时,等价于 const char * str = "\xe6\x88\x91\xe6\x98\xaf\xe6\xb1\x89\xe5\xad\x97";注意:这个说法不全对,比如保存成带BOM的UTF-8,用cl编译器时,汉字本身是UTF-8编码,但程序内保存时却是对应的GBK编码。 明确概念3: QString 内部采用的是Unicode。QString内部采用的是 Unicode,它可以同时存放GBK中的字符"我是汉字",BIG5中的字符"扂岆犖趼" 以及Latin-1中的字符"ÎÒÊǺº×Ö"。 一个问题是,源代码中的这8个字节"\xce\xd2\xca\xc7\xba\xba\xd7\xd6",该怎么转换成Unicode并存到 QString 内?按照GBK、BIG5、Latin-1还是其他方式... 在你不告诉它的情况下,它默认选择了Latin-1,于是8个字符"ÎÒÊǺº×Ö"的unicode码被存进了QString中。最终,8个Latin字符出现在你期盼看到4中文字符的地方,所谓的乱码出现了 QString 工作方式const char * str = "我是汉字"; QString a= str;其实很简单的一个问题,当你需要从窄字符串 char* 转成Unicode的QString字符串的,你需要告诉QString你的这串char* 中究竟是什么编码?GBK、BIG5、Latin-1 理想情况就是:将char* 传给QString时,同时告诉QString自己的编码是什么: 就像下面的函数一样,QString的成员函数知道按照何种编码来处理 C 字符串 QString QString::fromAscii ( const char * str, int size = -1 ) QString QString::fromLatin1 ( const char * str, int size = -1 ) QString QString::fromLocal8Bit ( const char * str, int size = -1 ) QString QString::fromUtf8 ( const char * str, int size = -1 )单QString 只提供了这几个成员函数,远远满足不了大家的需求,比如,在简体中文Windows下,local8Bit是GBK,可是有一个char串是 BIG5 或 Latin-2怎么办? 那就动用强大的QTextCodec吧,首先QTextCodec肯定知道自己所负责的编码的,然后你把一个char串送给它,它就能正确将其转成Unicode了。 QString QTextCodec::toUnicode ( const char * chars ) const可是这个调用太麻烦了,我就想直接 QString a= str;或 QString a(str);这样用怎么办? 这样一来肯定没办法同时告诉 QString 你的str是何种编码了,只能通过其他方式了。这也就是开头提到的 QTextCodec::setCodecForCStrings(QTextCodec::codecForName("GBK")); QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));设置QString默认采用的编码。而究竟采用哪一个,一般来说就是源代码是GBK,就用GBK,源代码是UTF-8就用UTF-8。但有一个例外,如果你保存成了带BOM的UTF-8而且用的微软的cl编译器,此时仍是GBK。
|
CopyRight 2018-2019 实验室设备网 版权所有 |