赞
踩
中文处理的时候,编译器首先解析源码字符集,根据具体情况将源码字符集解析为执行字符集,再将执行字符集转换为QString的编码(unicode)。QString的编码是固定的,要想整个过程无乱码,那么源码字符集到执行字符集的转换必须确定。换句话说就是编译器必须明确文件的编码和执行字符集。这个不同的编译器的逻辑是不一样的。以MSVC和Mingw为例分析:
源码字符集:源文件有BOM的情况下按BOM解释,无则使用本地Locale字符集(随系统设置而变)。
执行字符集:使用本地Locale字符集(随系统设置而变)。
源码字符集和执行字符集默认都按utf-8解析。
因此乱码的原因有:
最好的解决方案是将源码保存成utf8 bom,执行字符集也选为utf8
对于MSVC,源码字符集之所以保存成 bom是因为只有bom 编译器才能识别出来源码字符集,执行字符集设置为utf8在C++98的MSVC上是没有什么好办法的,只能使用QString::fromUtf8设置转换算法。c++ 11比较方便,提供了设置执行字符集的方法 #pragma execution_character_set("utf-8")。
之所以说这是最好的解决方案,是因为这种设置在qt5以上的版本中具有良好的跨平台性,Mingw和GCC都支持这种方案。
采用这种方案无需再写QString::fromxxx()函数(此中情况下发现无论是在msvc还是mingw下,对于中文常量的处理加不加fromUtf8都能正常处理,分析了一部分源码和注释后猜测是因为从const char*到QString的隐式转换内部使用了QStringData保存字符串的空间,然后这个字符串 从 utf-8转码为unicode并拷贝到data)。
使用vs2010以上版本开发程序的时候,可以安装ForceUTF8(with BOM)插件,能够使新创建的工程文件都是BOM格式。
#pragma execution_character_set("utf-8")不需要硬编码到代码中,可以使用inc文件在pri文件中设置编译器和链接器flag参数即可
win32-msvc*:QMAKE_CXXFLAGS += -FI\"$$PWD/xxx.inc\"
win32-msvc*:QMAKE_CFLAGS += -FI\"$$PWD/xxx.inc\"
另外有一点需要注意,编译器根据ui文件生成的ui_xxx.h文件默认编码是utf-8(无BOM),里面涉及到的汉字都已经转换成了字符编码,所以ui文件生成的源码无需特殊处理。
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
Qt5版本取消了QTextCodec::setCodecForTr()和QTextCodec::setCodecForCStrings(方法,只剩下setCodecForLocale,这一个函数也只影响Qt对toLocal8Bit相关函数的编码方式。并且QObject::tr是用于程序国际化的,可以使界面文字翻译成不同的语言。如果使用QObject::tr,就应该全部用英文表示,然后借助Linguist翻译成中文,这样不会乱码了。
QStringLiteral是一个宏,在支持lambda表达式的c++11中,直接解析源码字符集到宽字节。不支持lambda的编译环境中等同于fromUtf8
只要保证源码字符集编译器识别正确就不会出现乱码,因为它是直接转换成了宽字符,和执行字符集没有关系(个人认为)
这种情况下,设置源码字符集为utf-8 bom,编译器因为bom的存在能够正确识别出源码字符集。但是执行字符集并没有设置,所以采用window系统默认的gbk作为执行字符集。因为QStringLiteral不经过执行字符集的转换,所以显示正常。
另外一种情况,源码字符集为utf-8,因为没有bom,msvc不知道这是什么编码,默认当成window系统默认的gbk作为源码字符集。但是真实编码应该是utf-8,源码字符集错了,转换成宽字节的时候也不正常了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。