首先说明几个基础概念

  • UTF-8 BOM 和 UTF-8。BOM在文件头位置占三个字节,用来标识UTF-8编码,软件通过BOM来识别这个文件是否是UTF-8编码。
  • 源码字符集。源码文件使用某种编码格式保存。
  • 执行字符集。可执行程序内保存的编码(程序执行时内存中字符串编码)。
  • QString中统一采用utf-16(Unicode)存储字符串。
  • QString::fromxxx()函数。代表将字符串以对应格式去解析成Unicode,fromLocal8Bit()代表使用本地字符集(系统设置)转换成Unicode;fromUtf8代表从utf-8转换成Unicode。Qt程序运行的时候字符串编码在QString中实际都是以unicode编码存储的,通过使用QString::fromxxx()转换成转换成unicode存到QString中。

乱码产生的原因

中文处理的时候,编译器首先解析源码字符集,根据具体情况将源码字符集解析为执行字符集,再将执行字符集转换为QString的编码(unicode)。QString的编码是固定的,要想整个过程无乱码,那么源码字符集到执行字符集的转换必须确定。换句话说就是编译器必须明确文件的编码和执行字符集。这个不同的编译器的逻辑是不一样的。以MSVC和Mingw为例分析:

  • MSVC

源码字符集:源文件有BOM的情况下按BOM解释,无则使用本地Locale字符集(随系统设置而变)。

执行字符集:使用本地Locale字符集(随系统设置而变)。

  • Mingw

源码字符集和执行字符集默认都按utf-8解析。

因此乱码的原因有:

  1. 编译器解读源码字符集错误,比如utf-8的源码不带bom编译器会当成locale,执行字符集也是locale所以不需要转换,但是实际utf-8的编码到locale是需要转换的。
  2. 源码字符集到执行字符集的转换错误。比如需要解析执行字符集utf-8,需要使用fromUtf8。但是却使用了其它的转换方式fromXXX,这是使用了错误的转换算法。
  3. 字符解析错误。比如程序中的字符串二进制是utf-8的,设置执行字符集是loacle,那么解析就会出错。

解决方案

最好的解决方案是将源码保存成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参数即可

  1. 将#pragma execution_character_set("utf-8")保存在xxx.inc中
  2. 在pri中添加:

win32-msvc*:QMAKE_CXXFLAGS += -FI\"$$PWD/xxx.inc\"

win32-msvc*:QMAKE_CFLAGS += -FI\"$$PWD/xxx.inc\"

另外有一点需要注意,编译器根据ui文件生成的ui_xxx.h文件默认编码是utf-8(无BOM),里面涉及到的汉字都已经转换成了字符编码,所以ui文件生成的源码无需特殊处理。

应该避免的解决方案

  • qt5之前有一种很不推荐的解决方案:

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也可以处理汉字乱码,其实它的功能是用来减少一次临时拷贝对象,用来提升性能的,有部分编码转换的功能,但是说它可以处理乱码,经过分析和实践发现毫无道理。

QStringLiteral是一个宏,在支持lambda表达式的c++11中,直接解析源码字符集到宽字节。不支持lambda的编译环境中等同于fromUtf8

只要保证源码字符集编译器识别正确就不会出现乱码,因为它是直接转换成了宽字符,和执行字符集没有关系(个人认为)

这种情况下,设置源码字符集为utf-8 bom,编译器因为bom的存在能够正确识别出源码字符集。但是执行字符集并没有设置,所以采用window系统默认的gbk作为执行字符集。因为QStringLiteral不经过执行字符集的转换,所以显示正常。

另外一种情况,源码字符集为utf-8,因为没有bom,msvc不知道这是什么编码,默认当成window系统默认的gbk作为源码字符集。但是真实编码应该是utf-8,源码字符集错了,转换成宽字节的时候也不正常了。

qt中文乱码原因分析及解决方案相关推荐

  1. Qt中文乱码原因及解决方案

    本文主要分析了基于windows系统msvc2013编译器的Qt中文乱码. 概念 字库表:是一个系统支持的文字,符号,数字的集合. 编码字符集(字符集):我们平时所说的字符集就是这个,计算机以二进制的 ...

  2. 彻底解决Qt中文乱码以及汉字编码的问题(UTF-8/GBK)

    尊重作者,支持原创,如需转载,请附上原地址:https://blog.csdn.net/libaineu2004/article/details/19245205 一.Qt Creator环境设置 1 ...

  3. Qt中文乱码解决思路

    最近项目中遇到不少的Qt中文乱码的问题,主要原因是客户的需求比较多,Qt版本有用4的版本的也有用5的版本,并且还有windows与linux跨平台的需求. 经常出现个问题是windows的解决了,源代 ...

  4. zhs16gbk对应mysql_NLS_LANG 数据库字符集中文乱码问题分析和解决

    前言 已经有 3 年多没再关心或者遇到编码格式的问题了,一是离 Oracle 数据库操作远了,二是现在的 Terminal,IDE 和操作系统语言环境配置都很标准,比如清一色的 UTF-8 编码和 U ...

  5. php源码 乱码 通达oa_php中文乱码问题的终极解决方案汇总

    前言 本文主要给大家介绍了关于php中文乱码问题的终极解决方案,分享出来供大家参考学习,在开始之前,我们先来谈谈为什么会出现中文乱码? 很多新手朋友学习PHP的时候,发现程序中的中文在输出的时候会出现 ...

  6. [转载]关于中文乱码问题的一些解决方案和经验

    关于中文乱码问题的一些解决方案和经验 1.字节和unicode java内核是unicode的,就连class文件也是,但是很多媒体,包括文件/流的保存方式是使用字节流的.因此java要对这些字节流经 ...

  7. QT中文乱码解决思路和方法汇总

    QT中文乱码解决思路和方法 中文编码一律使用QString::fromLocal8Bit()接口,原因是为了支持QT4版本.QStringLiteral()方法也可以使用,它是支持QT5版本的: CP ...

  8. QT中文乱码解决方法2

    转载自:http://blog.163.com/seven_7_one/blog/static/162606412201032955449489/ QT中文乱码的解 2010-04-29 17:54: ...

  9. 万字长文总结JAVA几种常见的编码格式和乱码原因分析

    你知道的越多,不知道的就越多,业余的像一棵小草! 你来,我们一起精进!你不来,我和你的竞争对手一起精进! 编辑:业余草 developer.ibm.com/zh/articles/j-lo-chine ...

最新文章

  1. ON、WHERE、HAVING的区别
  2. js实现图片轮播(终结版)
  3. QQ牧场在高速模式下的一些小bug
  4. C语言库函数的实战之一
  5. 常见设备分辨率大小,响应式必备啊
  6. 对C语言进行调试的最好方法是什么?
  7. html设置div页面最底,使用css让大图片不超过网页宽度
  8. Spring MVC 实践笔记
  9. 科兴生物董事长:两针建立免疫记忆 三针后抗体提升十倍
  10. curl php 禁用ip6,CentOS 6禁用IPv6解决curl Couldn’t resolve host或dns解析慢
  11. 记一次微信数据库解密过程
  12. Ubuntu——系统扩容(加硬盘)的学习笔记
  13. 新手如何使用Docker来搭建PHP开发环境?
  14. webpack.config.js====CSS相关:插件optimize-css-assets-webpack-plugin
  15. tp前后端不分离源码_Thinkphp5.0+Vue2.0前后台分离框架通使用后端源码
  16. 大白菜装机教程win10_大白菜U盘启动工具|大白菜超级U盘启动制作工具 V6.0_2009.25官方版下载...
  17. 美团网站底部超链接部分设计实现
  18. 安装java的心得体会_java实训心得体会范文
  19. Android 如何优雅的实现控件计时功能
  20. 我的世界JAVA挂机杀怪有经验_我的世界如何快速获得经验?

热门文章

  1. matlab 坐标轴刻度朝外_Matlab 绘图 坐标轴 刻度
  2. 庖丁解牛linux内核 百度云,庖丁解牛Linux内核-1
  3. 淘宝京东APP节日更新布局 实现方式
  4. VUE全家桶项目实战-- 4.后台首页布局
  5. 【技术贴】怎么装系统?到店里重装系统,装驱动。价钱多少 ?
  6. QT实现加载百度离线地图
  7. java两张图片拼接
  8. 通过“偷”的方式对网站进行推广
  9. 从 几 个应用入手 了解为什么灵魂绑定代币将为 DeFi 带来大规模采用
  10. 非线性控制2.0——模糊逼近