首页 > 编程语言 >Qt杂谈5.浅谈Qt程序乱码那些事

Qt杂谈5.浅谈Qt程序乱码那些事

时间:2023-07-03 22:13:13浏览次数:40  
标签:编码 UTF Qt 字符 乱码 Unicode 字符串 浅谈

1 为啥聊这个?

你是否也在为Qt程序乱码的问题发愁?网上查了一大堆文章,十篇文章九篇一样,虽然碰运气把问题解决了,但是下次遇到同样的问题还是无从下手,如果你想从根本上理解并解决这个问题,那么可以看看这篇文章,希望能帮到你。

2 从代码出发

2.1 使用的Qt版本

本人的测试环境:
Qt版本:Desktop_Qt_5_12_3_MSVC2017_64bit
mingw编译器一般不会遇到乱码问题,这里主要讲MSVC编译器。
新建一个工程:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    qDebug() << "我和你";
}

2.2 代码页(936)问题

错误如下:

..\AviationPro\mainwindow.cpp: warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为Unicode格式以防止数据丢失
..\AviationPro\mainwindow.cpp(16): error C2001: 常量中有换行符
..\AviationPro\mainwindow.cpp(17): error C2143: 语法错误: 缺少“;”(在“}”的前面)

首先,需要搞清楚,什么是当前代码页(936)?

当前代码页是指操作系统的本地字符编码设置。代码页(Code Page)是一种字符编码方案,用于表示文本中的字符集合以及字符与数字之间的映射关系。在Windows操作系统中,当前代码页指的是系统的本地字符编码设置。在不同的地区或语言环境中,可能会使用不同的代码页作为默认的字符编码方式。例如,代码页936在中文环境下通常指的是GBK编码(中文简体)。它是一种单字节编码,无法表示Unicode字符。如果源文件中包含了无法在当前的 936 代码页中表示的 Unicode 字符,就会出现上述错误提示。

这个时候可以这样处理:

点击确认,回到源码编辑页面,随便编辑下文件,Ctrl+S保存文件,这个时候文件就变成了UTF-8-BOM编码的了。此时再次编译,上面的错误消失了,编译也成功了。
解释下原因:

当一个源文件添加了BOM之后,在读取该文件时,编译器就能正确识别文件的编码格式,包括Unicode编码(如UTF-8和UTF-16),进而正确处理其中的Unicode字符,避免了字符丢失或解析错误。

2.3 输出乱码

经过上面的处理,源文件和编译过程都没问题了,但是运行时却出错了,输出如下:

19:35:47: Starting D:\QtPro\build-AviationPro-Desktop_Qt_5_12_3_MSVC2017_64bit-Debug\debug\AviationPro.exe ...
?????
19:35:53: D:/QtPro/build-AviationPro-Desktop_Qt_5_12_3_MSVC2017_64bit-Debug/debug/AviationPro.exe exited with code 0

本来要输出的‘我和你’变成了‘?????’,什玩意儿这是?
分析下原因:
首先我们使用notepad++打开可执行程序AviationPro.exe,搜索“我和你”,输出如下:

这是什么意思呢,MSVC编译自动将字符串转为ANSI编码了,对于中文来说,ANSI编码通常指代GBK编码或GB2312编码,然而,Qt程序在运行过程中会将字符串认为是Unicode编码来进行处理,那肯定是不行的。
那么问题来了,前面不是把源文件改成UTF-8-BOM编码了嘛,为啥编译生成的exe还是ANSI编码?

说下原因:对于使用MSVC编译,使用UTF-8-BOM编码的源代码文件在编译过程中不会直接影响生成的可执行文件的字符集。
MSVC编译器默认情况下会使用与本地代码页相关联的字符集,通常被称为ANSI编码。这意味着生成的可执行文件将使用本地代码页定义的字符集作为默认字符集。虽然源代码文件使用 UTF-8-BOM 编码,但是在编译过程中,编译器会将源代码文件转换为内部编码,然后生成可执行文件。

因此,单纯使用UTF-8-BOM编码的源代码文件并不能直接改变生成的可执行文件的字符集。
接下来,我们继续探索。。

2.4 使用QString::fromLocal8Bit转换

修改代码如下:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    qDebug() <<  QString::fromLocal8Bit("我和你");
}

输出如下:

解释下原因:

QString::fromLocal8Bit 是 Qt 中的一个字符串转换函数,它的作用是将一个使用本地(系统默认的)字符编码(如ANSI编码)表示的字符串转换为Unicode编码的QString。

这应该懂了嘛,MSVC编译器将字符串转换为ANSI编码了,但是Qt运行时会将字符串转换为Unicode编码,所以需要转换下才能正常显示。

2.5 使用QStringLiteral 宏

除了上述方法,还可以这样:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    qDebug() <<  QStringLiteral("我和你");
}

输出结果如下:

先解释下QStringLiteral 宏是个啥?

QStringLiteral是Qt框架中的一个宏,用于创建一个指向编译时常量的QString对象,它会将字符串作为字面值存储在内存中,通常被存储在程序的数据段(.data 或 .rodata)中。当使用QStringLiteral宏创建QString对象时,这些字符串常量会按照原始的UTF-8编码形式存储在编译后的可执行文件中的数据段或只读数据段。在程序运行时,QString对象会根据需要将UTF-8编码的数据转换为内部的Unicode字符表示。

嗯哼,这下应该清楚了吧,这种情况下就不存在编码转换的问题了,顺便提一下,QStringLiteral宏带来了以下优势:

  1. 字符串优化:QStringLiteral可以在编译时对字符串进行优化处理。它会将字符串以字面值的形式存储在内存中,并且可以直接从编译器的字符串表中获取。这样可以减少运行时创建和销毁QString对象的开销,提升程序的执行效率;
  2. 避免不必要的复制:使用QStringLiteral可以避免不必要的字符串复制。普通的QString对象会在构造时复制一份字符串数据,而使用QStringLiteral则可以直接共享编译时的常量字符串数据,减少内存使用和内存拷贝;
  3. 安全性:QStringLiteral在编译时进行字符串类型检查,提前发现潜在的问题;
  4. 代码清晰度:使用QStringLiteral可以使代码更加简洁和清晰。由于编译时优化,字符串的创建和比较操作更加高效,可以提高代码的可读性和维护性。

2.6 使用pragma execution_character_set("utf-8")预处理

修改代码如下:

#pragma execution_character_set("utf-8") 
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    qDebug() <<  "我和你";
}


嗯,一切尽在掌控之中,解释下原因:

预处理指令#pragma execution_character_set("utf-8"),用于告诉MSVC编译器将源文件中的字符集设置为UTF-8。这样做可以确保源文件中的中文字符和其他非ASCII字符能够正确地被编译器解析和处理,避免出现乱码问题。

这个时候,我们再次使用notepad++打开可执行程序AviationPro.exe,搜索“我和你”,输出如下:

此时,中文字符串已经保存为UTF-8编码了,所以,本地编码的AviationPro.exe文件已经搜不到“我和你”字符了,Qt运行时也能够正常识别。
好了,一切豁然开朗。你开朗了吗?

3 总结

说了这么多,不知道大家有没有收获点什么,其实就两个要点,一个是编译时处理为的编码,一个是运行时需要的编码,一般来说MSVC编译器会将字符处理为本地编码(gbk),而Qt运行时默认使用Unicode编码,这就不一致了,所以会乱码。解决办法就是转换一下,或者告诉编译器怎么做。
补充一点,严格来讲,Unicode编码这种叫法不严谨,简单说明下:

Unicode是一个字符集,它为每个字符分配了一个唯一的编号,这些编号称为码点。Unicode字符集包含了世界上几乎所有的字符,包括各种语言的字符、符号、标点等。
UTF-8是一种编码方式,它定义了如何将Unicode字符集中的字符编码为字节序列。UTF-8使用可变长度的编码方式,根据字符的码点大小来确定所需的字节数。较小的字符使用较少的字节来编码,较大的字符使用更多的字节。UTF-8编码是一种向后兼容ASCII编码的方式,ASCII字符与UTF-8编码是完全一致的。
简而言之,Unicode是一个字符集,而UTF-8是一种将Unicode字符编码为字节序列的编码方式。Unicode是一种标准,而UTF-8是一种具体的实现方式。

好了,有不对的地方,希望大家不吝赐教。

标签:编码,UTF,Qt,字符,乱码,Unicode,字符串,浅谈
From: https://www.cnblogs.com/luoxiang/p/16974176.html

相关文章

  • 浅谈安科瑞EMS2.0能效管理平台在制药厂洁净室的电气设计与选型
    罗轩志安科瑞电气股份有限公上海嘉定201801摘要:从设计原则、动力配电、照明配电和通信等方面分析了在洁净室电气设计中应遵循的原则和应注意的问题,并通过附图详细表明了医药洁净室管线的密封处理方法。关键词:医药洁净室;药品生产质量管理规范;密封;照度;应急照明;防静电接地0引言随着......
  • pyqt5-样式设置
    1、介绍pyqt5中,允许通过类似css的层叠样式表的形式,直接为组件声明显示样式,比如设置字体、字体颜色和背景色等。具体的是,是通过QWidget类中声明的setStyle或setStyleSheet方法设置。setStyle(self,a0:QStyle)setStyleSheet(self,styleSheet:str)style(self)->QStylesty......
  • 串口接受不了消息,乱码问题
    收不了消息(一)发送消息,代码所写应该为接受后发送,但是并没有出现intmain(void){HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_USART1_UART_Init();uint8_tbyte;uint8_tlen;uint8_tbuf[32]="";while(1){ if(HAL_UART_Receive(&h......
  • 浅谈图论
    多源最短路算法(Floyd)说到最短路,就不得不提到松弛。所谓松弛,就是当存在\(w_{u,v}>w_{u,k}+w_{k,v}\)时,令\(w_{u,v}=w_{u,k}+w_{k,v}\)一般来说,松弛操作后,我们会用松弛后的边不断松弛其他边,而这,就是大部分最短路算法的思路。思考一下,若用DP的思想考虑,那么我们易设出状态\(f_{i......
  • 龙蜥7.9 rpm安装mqtt
    1、下载mqtt的rpm包,https://www.emqx.io/downloads?os=CentOS2、安装依赖,去http://rpmfind.net/下载openssl11和openssl11-libsopenssl11-1.1.1k-5.el7.x86_64.rpmopenssl11-libs-1.1.1k-5.el7.x86_64.rpm3、逐个安装lib、openssl11、emqx三个包,即可,后面的配置就和以前一样了......
  • Linux下的tty终端显示中文乱码解决方法
    1.下载字体fbterm  sudoapt-getinstallfbterm 2.完成后运行  sudofbterm 3.更改字体和字体大小  vi~/.fbtermrc    font-names=UbuntuMono    font-size=14   tty界面下是无法输入中文输入法  https://blog.csdn.net/maybe_frank/article......
  • Qt6.x版本下载与安装
    自从5.15版本开始,Qt对非商业版本(开源版本)不提供已经制作好的离线exe安装包,Qt6.x版本需要在线下载安装。 一、准备因为是在线下载,QT属于国外研发,下载速度受到限制。所以通过Fiddler更换代理,采用国内镜像进行下载。Fiddler下载地址:https://www.telerik.com/download/fiddler......
  • qt 网络编程
    UDP是一个轻量级、不可靠、面向数据报的、无连接的协议,多用于可靠性要求不严格,不是非常重要的传输。//服务器端  h1=newQUdpSocket(this);h1.bind(5555,QUdpSocket::ShareAddress);//绑定端口号connect(h1,&QUdpSocket::readyRead,this,&xx::YY);//接受到其它地方发......
  • 浅谈线性规划
    以前学了很多次都没学明白,今天再来看看。本文不会涉及单纯形法的知识点讲解,大部分题目侧重于线性规划对偶。同样本文不会涉及相关知识点的证明,或是线性规划解的整数性说明,毕竟这只是一个总结性的文章。拉格朗日对偶部分没学会,暂鸽。线性规划标准型对于任意线性规划,容易通过......
  • qt this application failed to start because it could notfoind orloadthe Qt pla
    qt程序报错:thisapplicationfailedtostartbecauseitcouldnotfoind orloadtheQt platform ===================================C:\Users\lenovo>C:\Users\lenovo>C:\Users\lenovo>cdD:\software\Qt\install\Qt5_12_12\5.12.12\msvc2015_64\b......