当前位置: 首页 > news >正文

Qt 4.8.7 + MSVC 中文乱码问题深入分析

此问题很常见,然而网上关于此问题的分析大多不够深刻,甚至有错误;加之Qt5又更改了一些编码策略,而很多文章并未提及版本问题,或是就算提了,读者也不重视。这些因素很容易让读者产生误导。今日我彻底研究透了这个问题,在此记录。

环境:Qt 4.8.7, Qt Creator 4.2.2, MSVC 2015

Qt 4.8.7 + MSVC 的中文乱码问题,实际上有两层原因。

第一层:MSVC 不识别无 BOM 的 UTF-8

Qt Creator 默认源代码文件编码是无BOM的UTF-8,而MSVC编译器会误认为这是本地多字节字符集(MBCS)编码(对于简中地区,即GBK,代码页936)。

解决方法1(推荐):Qt Creator选项—文本编辑器—文件编码—UTF8 BOM——如果编码是UTF8则添加—确定。
解决方法2:Qt Creator选项—文本编辑器—文件编码—默认编码—GBK—确定。

注意:修改以上两种方法提及的设置后,Qt Creator并不会自动修改已保存的文件的编码或BOM。我们需要修改一下含中文的文件,重新Ctrl+S保存,这样才能将这些设置应用于这些文件。

第二层:QString 构造函数默认假定的文本编码不正确

我们代码中的字符串,特别是用于测试这个乱码问题的字符串,一般都是C样式的,即用一对双引号包围的const char []类型字符串字面量,如 "Hello World" 。然而 Qt 里很多函数的参数要求的字符串类型都是 QString,我们填入这种C样式字符串时就会有个隐式转换,转为QString类型,其实也就是QString这个构造函数在帮我们转换:

explicit QString::QString(const char* ch)

 然而const char*类型只表明了这个字符串是多字节字符集,却没指明是哪一种,他可能是GBK, UTF-8等等,甚至可能是跟咱这边八竿子打不着的西欧语言字符集Latin-1(ISO-8859-1)。不加声明的话,MSVC默认我们的字符串字面量是本地多字节字符集(MBCS),即GBK编码,如下图左侧“标题title”文本所示情况。而如果在这种C样式字符串的引号前加上“u8”二字,则MSVC就会认为此字符串是UTF-8编码,如下图右侧“文本text”文本所示情况。

 MSVC在我们有或没有声明的情况下判断出了此字符串的编码后,对此字符串进行编码,也就是将它们转换为二进制的字节数据,传给QString的构造函数。

注意:
①即使在上一层问题的解决中,我们选择了保留UTF-8,加上BOM供MSVC识别,以上所述MSVC对C样式字符串的编码的解析方式仍然成立。他不会因为你的源码文件是UTF-8编码,就将其中的这种字符串优先视为UTF-8。所以上一层问题你选择了哪种解决方法对这一层问题是没有影响的。
②“u8”标记只是给MSVC编译器的提示,MSVC处理后,不管是加了u8还是没加,一律变成const char[]这样的字节数组。也就是说,有没有u8,QString的构造函数是不知道的,看不见的。他只知道传进来了一个const char* 类型。

传给QString的构造函数后,QString要解码这些二进制数据,也就是将它们映射到可显示(我们能看懂)的字符上。由于这些数据不能体现编码,他就要猜。咱当然希望他猜是GBK啦,但是事与愿违,Qt库毕竟不是中国人写的。他默认猜成西欧语言字符集Latin-1(如图)!这就会导致我们在代码里写了些汉字,却显示出一堆拉丁字母甚至音标。这也是为何在没有QString参与的情况下只解决第一层问题就好了,例如控制台窗口的std::cout,而在需要把const char*转换成QString时就又会出问题。

那么解决思路已经很明显了。要么修改它的设置,让他猜成GBK(或UTF-8),要么明明白白的告诉他我们的字符串是啥编码(使用 QString::fromXXX 函数)。

解决方法1(推荐):在 QApplication 对象创建前将“C样式字符串的编码(CodecForCStrings)”设为UTF-8,并在每个含中文的字符串字面量的前导引号前加上u8二字(如QString str(u8"这是中文");)。设置“C样式字符串的编码”的方法是:在程序的入口点(main函数)中最开始的位置加上图中这句代码(别忘了加头文件):

QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));

解决方法2: 跟方法1一样修改“C样式字符串的编码”,但设为本地多字节字符集(MBCS,一般是GBK),代码中的字符串字面量不加“u8”(如QString str("这是中文");)。具体方法和上条类似,不再赘述,但main函数中加的那句代码改为:

QTextCodec::setCodecForCStrings(QTextCodec::codecForLocale());

解决方法3: 在每个字符串字面量的前导引号前加上u8,并用 QString::fromUtf8() 包裹,如图:

解决方法4:字符串字面量的前导引号前不加u8,并用 QString::fromLocal8Bit() 包裹,如图:


依次解决以上两层问题后,中文就不再乱码了。再次强调,本文只针对 Qt 4.8.7 + MSVC2015 环境提供问题原理和解决方案,Qt5就不一样了,说不定微软也会在未来的MSVC中添加对无BOM的UTF-8文件的识别。那时,问题的解决将简单很多。

szx0427 作于 2024/07/17

相关文章:

Qt 4.8.7 + MSVC 中文乱码问题深入分析

此问题很常见,然而网上关于此问题的分析大多不够深刻,甚至有错误;加之Qt5又更改了一些编码策略,而很多文章并未提及版本问题,或是就算提了,读者也不重视。这些因素很容易让读者产生误导。今日我彻底研究透了…...

IDEA的常见代码模板的使用

《IDEA破解、配置、使用技巧与实战教程》系列文章目录 第一章 IDEA破解与HelloWorld的实战编写 第二章 IDEA的详细设置 第三章 IDEA的工程与模块管理 第四章 IDEA的常见代码模板的使用 第五章 IDEA中常用的快捷键 第六章 IDEA的断点调试(Debug) 第七章 …...

arcgis怎么选取某个指定区域地方的数据,比如从全国乡镇数据选取长沙市乡镇数据

一共5个步骤,没一句废话,耐心看完。看完你就会在任何软件选取指定范围的数据了。 一、如图,先将数据加载到arcgis里面,我们要选取里面长沙市的范围数据。 二、选取长沙市的语句 “市” like ‘长沙%’ 切记,切记&…...

二、链表(1)

203.移除链表元素 创建一个虚拟哨兵头节点,就不用考虑原本头结点要不要删除 # Definition for singly-linked list. # class ListNode: # def __init__(self, val0, nextNone): # self.val val # self.next next class Solution:def remove…...

KAFKA搭建教程

KAFKA搭建教程 期待您的关注 KAFKA学习笔记 帮助更多人 目录 KAFKA搭建教程 1.下载Kafka并解压 2.添加环境变量 3.修改 server.properties 文件 4.将kafka复制到其它节点 5.修改node1、node2节点的broker.id 6.将master的环境变量同步到node1、 node2 7.启动zookeeper…...

Linux网络——套接字与UdpServer

目录 一、socket 编程接口 1.1 sockaddr 结构 1.2 socket 常见API 二、封装 InetAddr 三、网络字节序 四、封装通用 UdpServer 服务端 4.1 整体框架 4.2 类的初始化 4.2.1 socket 4.2.2 bind 4.2.3 创建流式套接字 4.2.4 填充结构体 4.3 服务器的运行 4.3.1 rec…...

SpringBoot源码深度解析

今天,聊聊SpringBoot的源码,本博客聊的版本为v2.0.3.RELEASE。目前SpringBoot的最新版为v3.3.2,可能目前有些公司使用的SpringBoot版本高于我这个版本。但是没关系,因为版本越新,新增的功能越多,反而对Spri…...

【Qt】常用控件

文章目录 QWidgetenabledgeometrywindow framewindowTitlewindowIconqrc资源管理windowOpacitycursorfonttoolTipfocusPolicystyleSheet 按钮类PushButtonRadioButtonCheckBoxSignals 显示类LabelLCDNumberProgressBarCalendar 输入类LineEditTextEditComboBoxSpinBoxDateTimeE…...

electron 主进程和渲染进程通信

在Electron中,主进程(main process)和渲染进程(renderer process)之间的通信是非常重要的,因为Electron应用通常会将用户界面(由Web技术如HTML, CSS, 和JavaScript构建)和原生功能(如系统对话框、文件I/O等)分开处理。主进程管理应用的生命周期和创建渲染进程,而渲染…...

【ARM】MDK-解决CMSIS_DAP.DLL missing报错

【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 记录解决CMSIS_DAP.DLL missing的报错情况,对应相关报错信息,供后续客户参考,快速解决客户问题。 2、 问题场景 客户进行硬件调试时,发现Target设置内有CMSIS_DAP.DL…...

CSS 的环境变量函数env()

在CSS中,env() 函数并不是传统意义上的“环境变量”函数,如你在编程语言中可能遇到的那样。相反,env() 是CSS中的一个函数,它用于访问由宿主环境(如浏览器)提供给CSS的自定义属性(也称为环境变量…...

数学建模--国赛备赛---TOPSIS算法

目录 1.准备部分 1.1提交材料 1.2MD5码相关要求 2.TOPSIS算法 2.1算法概述 2.2基本概念 2.3算法核心思想 2.4拓展思考 3.适用赛题 3.1适用赛题说明 3.2适用赛题举例 4.赛题分析 4.1指标的分类 4.2数据预处理 4.2.1区间型属性的变换 4.2.2向量规范化 4.3数据加…...

均值滤波算法及实现

均值滤波器的使用场景: 均值滤波器使用于处理一些如上述蓝色线的高斯噪声场景 红色曲线是经过均值滤波处理后的数据。主要因为均值滤波设置数据缓冲区(也即延时周期),使得测量值经过缓冲不会出现特别大的变化。 黄色曲线为高斯噪声…...

【Apache Doris】周FAQ集锦:第 16 期

【Apache Doris】周FAQ集锦:第 16 期 SQL问题数据操作问题运维常见问题其它问题关于社区 欢迎查阅本周的 Apache Doris 社区 FAQ 栏目! 在这个栏目中,每周将筛选社区反馈的热门问题和话题,重点回答并进行深入探讨。旨在为广大用户…...

单例模式_Golang

目录 一、单例模式 1.1 基本概念 1.2 使用场景 二、Golang实现 2.1 懒汉模式(Lazy Loading) 一、单例模式 1.1 基本概念 一个类只能生成一个实例,且该类能自行创建这个实例的一种模式,这个定义个人感觉可以拆的通俗一些,在项目的生命周…...

代码随想录 day 18 二叉树

第六章 二叉树part06 详细布置 530.二叉搜索树的最小绝对差 需要领悟一下二叉树遍历上双指针操作,优先掌握递归 题目链接/文章讲解:https://programmercarl.com/0530.%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E7%9A%84%E6%9C%80%E5%B0%8F%E7%B…...

降雨量预测 | Matlab基于ARIMA-RBF降雨量预测

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 降雨量预测 | Matlab基于ARIMA-RBF降雨量预测 注:程序和数据放在一个文件夹。 程序语言为matlab,程序可出预测效果图,指标图; 代码特点:参数化编程、参数可方便更改、代…...

包含示例和模板的流程文档指南

当您的业务扩展时,您会得到越来越多的移动部件,并且需要有人来跟踪复杂性。人员和任务需要以尽可能最高效的方式进行组织,并且您必须找到某种方法让员工知道如何执行有效完成工作所需的流程。 为了使流程可重复,需要对其进行记录…...

51单片机嵌入式开发:15、STC89C52RC操作蜂鸣器实现一个music音乐播放器的音乐盒

STC89C52RC操作蜂鸣器实现一个music音乐播放器的音乐盒 1 概述2 蜂鸣器操作方法3 蜂鸣器发出音声4 硬件电路5 软件实现6 整体工程:7 总结 1 概述 要实现一个基于STC89C52RC单片机的音乐盒,可以按照以下步骤进行: (1)硬…...

B树(B-Tree)数据结构

1. 什么是B树? B树(B-Tree)是一种多路搜索树,用于存储和检索大量数据。它是自适应的,适用于各种存储设备和各种数据量。B树的特点是高效的搜索、插入和删除操作,且可以在各种情况下保持树的平衡。 2. B树…...

Linux输入子系统实战:从struct input_event到鼠标、键盘、触屏事件解析与编程

1. Linux输入子系统入门:从设备文件到事件流 刚接触Linux输入子系统时,我花了整整三天才搞明白/dev/input/eventX这些神秘文件背后的门道。简单来说,Linux把所有的输入设备——键盘、鼠标、触摸屏、游戏手柄——都抽象成了文件。当你按下键盘…...

蓝牙低功耗基-蓝牙广播

概述 广告功能是任何蓝牙LE连接中的一个关键要素。对不同的广告参数、其含义以及如何通过调整这些参数来实现应用目标(无论是降低功耗、提高可靠性还是加快设备发现过程)建立基本的理解是十分重要的。 蓝牙LE中的广告功能主要用于两个主要目的。一是向邻近设备广播数据&#…...

别再只会用HttpClient了!用C# Socket手搓一个TCP聊天室(WinForms实战)

用C# Socket构建WinForms聊天室:从零实现TCP通信实战 第一次接触网络编程时,看着那些晦涩的协议文档和黑底白字的命令行界面,总觉得离实际应用很远。直到把Socket和WinForms结合起来,才发现原来网络通信可以如此直观——消息在文本…...

Obsidian页面美化全攻略:自定义行间距与页面宽度,打造舒适阅读体验

Obsidian视觉调优实战:从行间距到页面宽度的沉浸式写作体验设计 在数字笔记工具百花齐放的今天,Obsidian凭借其本地优先、双向链接和高度可定制的特性,已经成为知识工作者的首选工具之一。但默认的界面设计往往难以满足长时间写作和阅读的需求…...

GAT1400跨级订阅避坑指南:从‘上下级’关系到稳定接收通知的完整配置

GAT1400跨级订阅实战解析:构建稳定多级视图库通信网络 在公安、交通等行业的视频监控系统集成中,GAT1400标准已成为实现多级平台数据共享的技术基石。作为系统集成工程师,我们常常需要面对A、B、C三级甚至更多层级平台间的复杂订阅关系配置。…...

[实战指南] 基于STM32 DCMI接口的OV2640图像采集与实时显示系统

1. OV2640摄像头基础解析 OV2640这颗200万像素的CMOS传感器,可以说是嵌入式视觉项目的性价比之选。我第一次用它做项目时,发现它最吸引人的特点是支持JPEG压缩输出——这意味着在1600x1200分辨率下,数据量能从3.8MB压缩到300KB左右&#xff0…...

遥感领域研究生投稿指南:如何根据2021-2022年JCR/中科院分区快速锁定目标期刊

遥感领域研究生投稿指南:数据驱动的期刊选择策略 第一次投稿就像在陌生的城市找路——手里有地图,但每条街看起来都差不多。去年这个时候,我盯着二十多个遥感期刊的分区数据发愁,直到导师点醒我:"分区不是用来膜…...

Blender骨骼命名太乱?手把手教你自定义Auto IK Rigger的JSON配置,适配任何骨架

Blender骨骼命名太乱?手把手教你自定义Auto IK Rigger的JSON配置,适配任何骨架 在三维角色动画制作中,骨骼绑定是最耗时的环节之一。不同软件、不同团队甚至不同项目都可能采用完全不同的骨骼命名规则,这给跨平台协作和插件使用带…...

轻松玩转树莓派Pico之五、FreeRTOS多任务实战

1. 为什么要在树莓派Pico上跑FreeRTOS? 树莓派Pico搭载的RP2040芯片虽然定位为微控制器,但其双核Cortex-M0架构和264KB的SRAM资源,在嵌入式领域已经算是"大内存"配置了。我刚开始玩Pico时也习惯用裸机编程,直到有一次需…...

告别第三方API:SpringBoot项目集成ip2region离线IP库的完整配置流程(附工具类)

SpringBoot深度整合ip2region:从离线IP定位到微服务架构实践 在Web应用开发中,获取用户地理位置信息是常见的需求场景。无论是内容分发、风控系统还是数据分析,IP属地信息都能为业务决策提供重要参考。传统方案通常依赖第三方API服务&#xf…...