目录

一、术语解释

1、编辑器(editor)

2、编译器(compiler)

3、源文件字符编码

4、执行文件字符编码

5、Unicode

二、Qt中的字符串

1.char*和std::string

2.QString

3.QTextCodec

三、Qt中乱码总结

1、问题

2、灵感

3、QString构造函数、translate、tr

4、解决办法

5、测试

四、Qt5乱码问题解决 ​​​​​​​


一、术语解释

首先还是解释一下字符编码相关的一些概念吧,可能有点啰嗦

1、编辑器(editor)

就是我们编辑源文件用的文本编辑器

当然集成开发环境都带有非常优秀的文本编辑功能啦,比如VS、QtCreator等。我们日常开发是不是直接打开IDE,经过一系列创建项目、配置项目等操作就可以撸代码啦,通常很少去设置什么字符编码之类的东西,但是QtCreator里边有设置字符编码的选项,不知道大家有没有操作过呢?

2、编译器(compiler)

就是把我们撸好的源文件编译成二进制文件的主要的软件啦,这里我们不谈链接器

比如有GCC编译器、MSVC编译器等

3、源文件字符编码

就是我们的编辑器所用的字符编码

我们用Visual Studio撸的源文件的编码是ANSI。这个ANSI编码还得啰嗦两句,它本身呀并不是真正的字符编码,只是微软为了让用户看起来自己的产品(Windows操作系统)的功能是一致的,所以起了一个ANSI的统称而已。在Windows系统里边有个代码页的东东,在不同的语言版本活跃的代码页是不同的。对于简体中文版本的Windows来说,活跃代码页是936,也就是ANSI表示的中文编码是GBK,英文编码就不用说了当然是ASCII或者更准确一点是Latin-1。对于日文版本的Windows系统来说,活跃的代码页、ANSI表示的编码又不同了。

用QtCreator撸的源文件的编码就是上图中设置的编码了,你也可以用其他的编辑器比如记事本、notepad++、Vi、UltraEdit等撸代码,那么源文件的字符编码就是对应editor所用的编码了。

4、执行文件字符编码

我们知道二进制可执行文件里边包含的大致就是一堆指令和数据,那么数据里边很有可能包含非英文字符,比如下面这段代码:

#include <stdio.h>
int main(void)
{const char *p = "字符编码";printf("%s\n", p);return 0;
}

程序中的“字符编码”这四个大字肯定保存在可执行文件(exe)的某个位置,当然是用二进制保存的。能决定可执行文件字符编码的就只有编译器啦,因为你的exe是编译器生成的嘛。当然程序中全部用英文那是没有问题的,但是作为一个非英语国家的程序员,你开发一个英文版的软件出来,别说自己英语水平不行,就算是能开发出来,把它卖给国内客户销路也不好吧哈哈。

那么编译器是如何决定可执行文件中的字符编码的呢?这个问题不同编译器的策略就不一样了,并且都有编译选项可以设置

GCC编译器:它生成的可执行文件的字符编码默认跟源文件的字符编码是一致的,可以通过-finput-charset和-fexec-charset选项显式告诉GCC源文件的字符编码是什么,生成的可执行文件字符编码是什么。大家可以做一个实验:在Windows下用记事本编辑上面的程序,把它拷贝到Linux下编译运行,输出的肯定是乱码。gcc --finput-charset=GBK -fexec-charset=UTF8 main.c这样编译就不会乱码了。

MSVC编译器:它生成的可执行文件的字符编码默认是locale(本地)编码,即跟活跃的代码页一致。它编译的时候会把源文件的字符编码翻译成本地编码,比如我们用notepad++使用UTF8编码编辑上面的代码,再用MSVC编译运行,Debug一下看看指针p的内存是怎样的,你会惊奇的发现,p指向了8个字节的内存,就是“字符编码”的GBK内码(0XD7D6  0XB7FB  0XB1E0  0XC2EB),GBK每个汉字用2字节编码。MSVC字符编码相关的编译选项是/source-charset和/execution-charset。

5、Unicode

Unicode本质上只是一个字符编码方案,或者叫字符编码标准,它本身并不提供具体的编码实现。可以把Unicode理解为一本字典,里边收录了全世界所有国家的文字,每个字符映射一个编号,用2字节表示,这个编号也叫做码点(值)。可能有人会问2字节只能表示65536个字符,全世界的语言文字应该不止这么多吧,我们中国就好几万了,确实不太够。这里又有一个平面(plane)的概念,把它理解为字典里的一页就好了,Unicode总共定义了17个平面。那么就可以这样理解:Unicode这本字典呢总共有17页,每一页有65536个字符,这下够了吧哈哈,当然有些页还是空白的呢(未定义)。这里边最重要的就是第一个平面(the first page),这个平面里边收录了大部分国家的最常用的字符,当然也有我们中文常见的汉字啦,称为基本平面BMP。

有了这个Unicode标准之后,就可以实现不同的字符编码了,比如英文的Latin-1,简体中文的GB2312、GBK,繁体中文的Big5,日文的Shift-JIS,俄语的KOI8-R,还有UTF8、UTF32、UTF16等等

二、Qt中的字符串

1.char*和std::string

不知道是否有人纠结过C/C++语言的char*和string到底表示的是什么编码呢?

对于这个问题呀,还是跟编译器有关,char*和string表示的就是执行文件的字符编码。如果没有指定字符编码编译选项,Linux下GCC编译char*和string表示的就是UTF8,Windows下MSVC编译char*和string表示的就是ANSI(中文是GBK)

2.QString

QString是对QChar的封装,使用的是Unicode编码,具体实现呢是用UTF16实现的。对于码点值超过65535的字符呢UTF16有自己的实现方案,用两个QChar表示一个字符,具体的编解码方法这里不讨论了,感兴趣自己研究吧。

3.QTextCodec

这个类为不同字符编码(比如GBK、Shift-JIS等)与Unicode即QString(QChar)之间进行翻译,它支持很多种字符编码,具体可以查看Qt帮助文档。

// 这里特别要注意!
// codecForName()函数用来设置将要被翻译的字符编码,例如本例中的"智能导航"
// 这个字符编码指的是执行文件的字符编码,不是源文件的字符编码
QTextCodec *codec = QTextCodec::codecForName("GB18030");// 即使源文件是UTF8编码,这里我用MSVC去编译,MSVC会自动把
// "智能导航"翻译成Windows本地编码即GBK
// 所以,codecForName()要设置为GB18030(它兼容GBK)而不是UTF8
QString chi = codec->toUnicode("智能导航");// 这个是上面的逆操作,所以gbk的内存刚好就是"智能导航"的GBK内码
QByteArray  gbk = codec->fromUnicode(chi);// 这里要非常非常注意
// toStdString()转换的结果跟源文件的字符编码一致!!!
// 如果源文件是用UTF8编辑的,那么这里的cstr就是UTF8编码
std::string cstr = fmt.toStdString();// txt跟执行文件编码一致,如果用MSVC编译就是GBK编码
const char *txt = "智能导航";

请仔细理解上面代码段中的注释!尤其是toStdString()这个函数要注意

三、Qt中乱码总结

Qt中的API和字符串相关的参数都是使用QString,也就是使用Unicode(UTF16)编码,只要我们使用的QString对象是Unicode编码,那么调用Qt API肯定不会乱码。Qt中出现乱码从如下几个方面考虑解决:

1、源文件是什么编码

2、Qt程序使用什么编译器

3、使用QTextCodec进行编码转换

4、使用QCoreApplication::translate()或QObject::tr()翻译

在Windows下用QtCreator开发可以配置MinGW(GCC的Windows版)和MSVC编译器,这个时候要注意理清源文件编码和执行文件编码。

在Linux下使用QtCreator开发通常都是UTF8编码和GCC编译器,源文件编码和执行文件编码一致

但是如果从Windows下拷贝文件到Linux中要注意,Windows的文件基本是ANSI编码,Linux文件通常是UTF8编码

1、问题

在Qt中使用下面的代码肯定会出现乱码:

QString title("错误提示");
// 然后把title传递给某个窗口函数
// 如果我们查看title的内容的话也会发现难以理解
dlg->setWindowTitle(title);

不知道有人遇到这样的问题没,即使加了translate或tr翻译还是会乱码!!!

// 还是乱码!
dlg->setWindowTitle(QObject::tr("错误提示"));

2、灵感

大家不知道有没有注意过,我们用QtDesigner设计UI界面,Qt的uic会把我们设计好的*.ui文件编译成一个头文件ui_*.h,在这个头文件中通常会有这样的代码:

void retranslateUi(QMainWindow *MainWindow)
{MainWindow->setWindowTitle(QCoreApplication::translate("MainWindow", "MainWindow", nullptr));pushButton->setText(QCoreApplication::translate("MainWindow", "\346\214\211\351\222\256", nullptr));
} // retranslateUi

translate()的参数中有一个奇怪的字符串"\346\214\211\351\222\256",明明界面上我输入的中文,这是什么东东莫名其妙?

其实这个字符串就是界面文本对应的UTF8编码,在C语言中可以用转义字符\ddd(三位八进制数)和\xhh(两位16进制数)表示任意一个字符,UTF8是用三个字节表示一个汉字,"\346\214\211\351\222\256"(注意是八进制)正好是"按钮"的UTF8编码即E68C89E992AE

3、QString构造函数、translate、tr

QString(const QByteArray &ba)

QString(const char *str)

translate(const char *context, const char *sourceText, const char *disambiguation = nullptr, int n = -1)

tr(const char *sourceText, const char *disambiguation = nullptr, int n = -1)

这里要注意,构造函数以及translate、tr都必须用UTF8编码表示的字符串传参才能正确转换成Unicode编码即QString

程序中直接写中文字符串,比如"错误提示",它其实是执行文件编码,MSVC编译的话就是GBK,这样是不能正确构造和转换为QString对象的

4、解决办法

比如想在Qt界面上显示"按钮",可以有以下几种方法:

// 正确构造"按钮"QString对象
QString txt("\346\214\211\351\222\256");// translate函数翻译"按钮"为Unicode编码
QString txt = qApp->translate("MyDialog", "\346\214\211\351\222\256");// tr函数翻译"按钮"为Unicode编码
QString txt = QObject::tr("\346\214\211\351\222\256");// 上面的字符串写成16进制也完全可以的
QString txt("\xe6\x8c\x89\xe9\x92\xae");QString txt = qApp->translate("MyDialog", "\xe6\x8c\x89\xe9\x92\xae");QString txt = QObject::tr("\xe6\x8c\x89\xe9\x92\xae");

如果说程序中写一串数字实在难以理解,那可以用下面的方法

// 使用QTextCodec翻译
QTextCodec *codec = QTextCodec::codecForName("GB18030");
QString txt = codec->toUnicode("按钮");

5、测试

下面是我的一段测试代码:环境QtCreator(UTF8编码) + MSVC

#include <QTextStream>
#include <QFile>
#include <QTextCodec>
#include <QDebug>
int main(void)
{time_t utc = time(NULL);// 源文件字符编码,由编辑器的编码决定// 二进制字符编码,编译器编译时决定//// GCC编译生成的二进制文件的字符编码默认和源文件字符编码一致,// 不会翻译成本地编码(即操作系统默认编码)// GCC可以使用-finput-charset和-fexec-charset选项指定二者//// MSVC编译器生成的二进制文件默认都是本地字符编码,即使源文件编码// 和本地编码不同,它也会翻译成本地编码// MSVC可以使用/source-charset和/execution-charset选项指定二者// codec字符编码指的是执行文件的编码// 这里我们明明使用UTF8编辑的程序,为什么却指定编码器为GB18030?// 因为我们用的是MSVC编译器,虽然源文件是UTF8,但是编译成二进制时MSVC// 会把它翻译成本地编码即ANSI编码(英文Latin1,中文GBK)QTextCodec *codec = QTextCodec::codecForName("GB18030");// GBK转换为Unicode(对Qt来讲是UTF16)QString fmt = codec->toUnicode("智能导航");// char*和std::string的字符编码是执行文件编码const char *msg = "智能导航";// 转换的结果和codecForName()设置的编码一致QByteArray  pgbk  = codec->fromUnicode(fmt);QString qstr_gbk(pgbk);QByteArray  putf8 = fmt.toUtf8();QString qstr_utf8(putf8);// toStdString()要特别注意,它转换的结果跟源文件编码一致,所以这里转换结果是UTF8编码std::string cstr = fmt.toStdString();qDebug() << msg;qDebug() << pgbk;qDebug() << putf8;qDebug() << qstr_utf8;return 0;
}

也可以参考这篇博客https://blog.csdn.net/brave_heart_lxl/article/details/7186631

四、Qt5乱码问题解决

以上描述的都是Qt4中存在的问题,在Qt5中就简单很多了,用宏QStringLiteral转换即可

#include <QDebug>
int main(void)
{QString str(QStringLiteral("智能导航"));qDebug() << str;return 0;
}

字符编码、QString编码、Qt界面乱码问题总结相关推荐

  1. Qt文件编码转换工具(三) Qt界面设计

    目录 下载链接 上一节为C++判断文件编码 本节为Qt界面设计 下载链接 Realase打包版本下载: Qt文本转化工具 realase版本 https://download.csdn.net/dow ...

  2. 解决Qt中文乱码以及汉字编码的问题(UTF-8/GBK)——ubuntu环境设置默认是utf-8,文件编码可使用Encodersoft批量转换

    解决Qt中文乱码以及汉字编码的问题(UTF-8/GBK)--ubuntu环境设置默认是utf-8,文件编码可使用Encodersoft批量转换 参考文章: (1)解决Qt中文乱码以及汉字编码的问题(U ...

  3. QT5 界面截图保存到本地+输出PDF/WORD格式文档+QT界面中文乱码及输出PDF中文乱码的解决(亲身实践并且成功)

    最近做了一个和QT5有关的项目,遇到很多问题也学习到不少,特意写下来希望帮到更多的人.(我的版本VS2017+QT5.12.0) 一.QT5截图并保存到本地 在头文件添加必须项 #include &l ...

  4. 【Java基础】Java中的char是否可以存储一个中文字符之理解字符字节以及编码集

    Java中的一个char采用的是Unicode编码集,占用两个字节,而一个中文字符也是两个字节,因此Java中的char是可以表示一个中文字符的. 但是在C/C++中由于采用的字符编码集是ASCII, ...

  5. 字符与编码(编码转换)

    作为一名程序员,肯定有被乱码困扰的时候,真到了百思不得其解的时候,就会觉得:英文程序员真幸福.但其实只要明白编码之间的转换规律,其实乱码还是很好解决的.我们都知道字符串在保存和传输的时候需要先经过编码 ...

  6. Computer:字符编码(ASCII编码/GBK编码/BASE64编码/UTF-8编码)的简介、案例应用(python中的编码格式及常见编码问题详解)之详细攻略

    Computer:字符编码(ASCII编码/GBK编码/BASE64编码/UTF-8编码)的简介.案例应用(python中的编码格式及常见编码问题详解)之详细攻略 目录 符串编码(ASCII编码/GB ...

  7. 编程时的编码、编码解码、编码乱码问题(ASCII、GBK、Unicode、UTF-32、UTF-8)

    编程时的编码.编码乱码问题(ASCII.GBK.Unicode.UTF-32.UTF-8) 1.ASCII (American Standard Code for Information Interc ...

  8. 字符常见的编码方式详解

    字符常见的编码方式 本人是做嵌入式开发的,当初第一次接触MDK时,被一个问题疑惑过,那就是在keil中的汉字注释复制到别的地方会出现乱码,还有编代码的时候,总会选择UTF-8编码方式.带着这些疑问我在 ...

  9. 火狐浏览器字体编码不能修改后页面乱码问题

    火狐浏览器字体编码不能修改后页面乱码问题 大无语事件 查看页面信息命名是utf-8但是还是照样乱码 上火狐官网一看 哦吼,没有字符编码修改了. 查了好久不知道咋回事儿呢 有的网站一个了乱码没有 有的全 ...

最新文章

  1. 计算 sigmoid 函数的导数
  2. 使用Mysql ID自增长时 在Mapper的insert里添加对应的代码
  3. 摩托面试续2-终于得到Offer了
  4. Machine Learning - Andrew Ng on Coursera (Week 5)
  5. 实现一个反向传播人工神经网络
  6. DataScience:对严重不均衡数据集进行多种采样策略(随机过抽样、SMOTE过采样、SMOTETomek综合采样、改变样本权重等)简介、经验总结之详细攻略
  7. 使用mongoose 在 Node中操作MongoDB数据库
  8. 222 Count Complete Tree Nodes
  9. (亲测可用)基于matlab的用自写函数来实现图像的灰度处理sobel canny算子边缘检测
  10. FFT算法的C语言实现
  11. 无人机和地面三维激光扫描仪在1:500城市基本地形图测绘中的应用
  12. 5.8G微米波雷达感应方案
  13. VBA 64 32 调用dll的区别
  14. Renix签名字段详解——网络测试仪实操
  15. Activiti7笔记(二)Activiti7一共涉及到25张表,哪些操作会涉及哪些表,每张表的作用是什么
  16. 他励直流电动机的启动
  17. 蓝牙协议spec文档免费下载官网下载(免费)
  18. [NOI 2008]假面舞会(综合图论)
  19. snmptrap 命令解析
  20. 用了这么久Chrome,我才知道原来广告能加速。。。

热门文章

  1. 黄光裕主宰不了国美的未来
  2. 因为编码产生的报错:UnicodeDecodeError: ‘utf-8‘ codec can‘t decode byte 0xbd in position 0: invalid start byte
  3. 樱花未开(更新完毕)
  4. 常用飞轮构型的角动量包络
  5. php实现手机归属地的查询、,PHP实现手机归属地查询API接口实现代码
  6. Android手机输入法按键监听-dispatchKeyEvent
  7. 云起时:记我们正在经历的教育之跃
  8. 高值选择器和低值选择器原理及应用
  9. 解决windows系统powershell命令行无法使用代理的问题
  10. 构建OpenStack私有云--第一步:配置Keystone服务