2019独角兽企业重金招聘Python工程师标准>>>

要搞清楚这个问题,先要弄明白编码。但是编码问题实在太复杂,这里肯定讲不开。

我先找一个例子,比如:"中文" 的 Unicode 码点/UTF8编码/GBK 分别是多少。

先去这个网站,输入 "中文" 查询对应的 Unicode 码点/UTF8编码: http://www.mytju.com/classcode/tools/encode_utf8.asp

Unicode的码点分别是(十进制):中(20013),文(25991)。 对应的UTF8编码分别(16进制): 中(E4B8AD),文(E69687)。

然后再去下面这个网站,输入 "中文" 查询对应的 GBK 编码: http://www.mytju.com/classcode/tools/encode_gb2312.asp

GBK编码16进制(GBK内码)分别是:中(D6D0),文(CEC4)。

现在已经知道了"中文"的UTF8和GBK编码的具体值。 我们再看看VC2010是怎么处理的。

1. 先看 无 BOM 的 UTF8 编码的代码 (utf8_no_bom.cpp)

// utf8 no bom
// 文件中包含不能在当前代码页(936)中表示的字符
#include <stdio.h>int main() {const char* str = "中文";for(int i = 0; i < sizeof(str); ++i) {printf("0x%x ", str[i]&0xFF);}return 0;// Output:// 0xe4 0xb8 0xad 0xe6
}

输出是:0xe4 0xb8 0xad 0xe6。 感觉好像是对的。

但是,先别急:VC编译时输出了一条警告信息: utf8_no_bom.cpp : warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。 请将该文件保存为 Unicode 格式以防止数据丢失。

潜台词就是,你这个代码有GBK不能表示的字符,请用Unicode方式保存。 VC根本就没把 代码(utf8_no_bom.cpp) 当作UTF8,VC只是把它作为GBK处理罢了。

那为什么又输出了正确的结果呢?

因为 VC 把 (utf8_no_bom.cpp) 当作 GBK,而编译时也要转换为本地编码(也是GBK)。 因此,UTF8编码的 "中文",被VC当作编码为 "0xe4 0xb8 0xad 0xe6" 的其他中文处理了。 VC已经不知道 "0xe4 0xb8 0xad 0xe6" 是对应 "中文" 字面值了。

但是在GBK(实际是无BOM的UTF8)转GBK的过程中,发现了一些UTF8编码的字符并不是 GBK能表达的合理方式,因此就出现了那个C4819编译警告。

2. 再看带BOM的UTF8是怎么处理的 (utf8_with_bom.cpp)

// utf8 with bom
#include <stdio.h>int main() {const char* str = "中文";for(int i = 0; i < sizeof(str); ++i) {printf("0x%x ", str[i]&0xFF);}return 0;// Output:// 0xd6 0xd0 0xce 0xc4
}

编译没有警告,但是输出有问题:0xd6 0xd0 0xce 0xc4。

源文件明明是 UTF8 编码的格式"0xe4 0xb8 0xad 0xe6", 怎么变成了 "0xd6 0xd0 0xce 0xc4" (这个是GBK编码)?

这就是VC私下干的好事:它自作聪明的将UTF8源代码转换为GBK处理了!

VC为何要做这样蠢事?

原因是为了兼容老的VC版本。 因为以前的VC不能处理UTF8,都是用本地编码处理的。

3. 在看看真的GBK是怎么处理的 (gbk.cpp)

// gbk
#include <stdio.h>int main() {const char* str = "中文";for(int i = 0; i < sizeof(str); ++i) {printf("0x%x ", str[i]&0xFF);}return 0;// Output:// 0xd6 0xd0 0xce 0xc4
}

没有编译错误,输出也和源代码一致:"0xd6 0xd0 0xce 0xc4"。

因为源文件就是GBK,cl在编译时GBK转化为GBK,没有改变字符串。

只是,现在很多人不想用GBK了(因为只能在中国地区用,不能表示全球字符)。


到这里,可以初步小结一下:

  1. VC编辑器和VC编译器是2个概念,VC编辑器支持UTF8并不能表示VC编译器也支持UTF8
  2. VC编辑器从2008?开始支持带BOM的UTF8(不带BOM的暂时没戏,因为会本地编码冲突)
  3. VC编译器从2010开始重要可以支持UTF8了(虽然支持方式很不优雅)

4. 看看VC2010是怎么处理带BOM的UTF8的 (utf8_with_bom_2010.cpp)

VC2010重要增加了UTF8的编译支持(#pragma execution_character_set("utf-8")), 具体查看:

http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/2f328917-4e99-40be-adfa-35cc17c9cdec

// utf8 with bom (VC2010), 这句是重点!
#pragma execution_character_set("utf-8")#include <stdio.h>int main() {const char* str = "中文";for(int i = 0; i < sizeof(str); ++i) {printf("0x%x ", str[i]&0xFF);}return 0;// Output:// 0xe4 0xb8 0xad 0xe6
}

没有编译错误,输出也和源代码一致:"0xe4 0xb8 0xad 0xe6"。

UTF8编码,UTF8输出。完美!


回到 Qt5 的中文输出问题。

Qt默认支持 VS2010/MinGW/Gcc 等编译器,而它们现在都已经真正支持UTF8了。

当然,VS2010 对UTF8的支持会入侵代码(#pragma execution_character_set("utf-8"))。

看看Qt官方论坛别人是怎么说的: http://qt-project.org/forums/viewthread/17617

Nothing special need to do, it will works by default. If the exec-charset of your your compiler is UTF-8.

简单的说,从Qt5开始,源代码就是默认UTF8编码的。

当然,VC2010编辑器对带BOM的UTF8也是认识,只可惜VC2010编译器根本承认它是UTF8!

在继续看官方论坛的回复:

You can write a simple example like this

  #include <QApplication>#include <QLabel>#if _MSC_VER >= 1600#pragma execution_character_set("utf-8")#endifint main(int argc, char *argv[]){QApplication a(argc, argv);QLabel label("ąśćółęńżź");label.show();return a.exec();}

If other people can reproduce your problem, you can file a bug.

教完整的解决方案(增加了Qt4/Qt5和非VC环境的判断):

// Coding: UTF-8(BOM)
#if defined(_MSC_VER) && (_MSC_VER >= 1600)
# pragma execution_character_set("utf-8")
#endif#include <QApplication>
#include <QTextCodec>
#include <QLabel>int main(int argc, char* argv[])
{QApplication app(argc, argv);#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
#if defined(_MSC_VER) && (_MSC_VER < 1600)QTextCodec::setCodecForTr(QTextCodec::codecForName("GB18030-0"));
#elseQTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
#endif
#endifQLabel *label = new QLabel(QObject::tr("你好!"));label->show();return app.exec();
}

有以下几种类型(源代码必须是带BOM的UTF8):

  • Qt5+/VC2010+: 包含了 # pragma execution_character_set("utf-8") 已经支持中文
  • Qt5/VC2008-: 这个暂时误解(我还没找到方法)
  • Qt4+/VC2008-: 采用以前老的方式, 指定代码为 "GB18030-0" 编码
  • Qt4/Qt5/Linux: 只要是默认的UTF8环境, 应该都没问题

其实这个问题不是Qt特有的, 追根溯源还是C/C++和编译器的问题.

即使是支持UTF16的Java也同样难逃此问题.

不过还好, Go语言 算是彻底了解决了这个问题. 以后转向 Go语言 了 !

转载于:https://my.oschina.net/chai2010/blog/119833

VC2010下Qt5的中文乱码问题相关推荐

  1. 【QT5.3】VS2013+QT5.3 中文乱码问题 解决方案

    VS2013+QT5.3 中文乱码问题 解决方案 网上很多关于QT中文乱码的问题及答案,但情况不同解决方法也不一样. 本方案适用于VS2013+QT5.3环境(编译器是VC) using namesp ...

  2. IE下Ajax 提交中文乱码问题

    2019独角兽企业重金招聘Python工程师标准>>> 今天碰到个乱码问题,在IE下post提交中文乱码,firefox下不会 对比两边提交的请求头信息发现问题出现在Content- ...

  3. oracle11g怎么显示中文,ORACLE11G中PLSQL中文显示乱码、Linux下sqlplus查询中文乱码

    问题描述: 本地是win7操作系统,cmd里面sqlplus进去连接oracle数据库,中文可以正常显示,但是plsql连接oracle数据库,中文显示乱码,还有xshell远程连接oracle服务器 ...

  4. windows下git bash中文乱码解决办法

    一.解决办法1:(直接上图) 1.在git bash下,右键 出现下图,选择options: 2.选择"Text" 3.将"Character set"设置为 ...

  5. 两种解决Qt5显示中文乱码的方法(使用QStringLiteral和#pragma execution_character_set(utf-8)两种方法)

    两种解决Qt5显示中文乱码的方法(使用QStringLiteral和#pragma execution_character_set("utf-8")两种方法) 升级到Qt5.X之后 ...

  6. chrome中文方框linux,问:Linux下Chrome标题栏中文乱码

    From:http://blog.csdn.net/loveaborn/article/details/29579787 在使用Linux的时候你会遇到一些奇奇怪怪的问题,不过,你会在解决这些问题的过 ...

  7. linux下的oracle中文乱码,Linux环境解决Oracle 中文乱码

    linux下Oracle显示中文乱码 1.Oracle数据库出现乱码的原因: 操作系统与服务器一致,但客户端与服务器字符集不一致 客户端与服务器一致,但操作系统与服务器不一致 2.解决办法: 设置相关 ...

  8. Linux下Java程序中文乱码问题研究

    Linux下Java程序中文乱码问题研究 摘  要:在一个项目的开发中,我用linux内核源代码和busybox源代码自己编译打造的操作系统mylinux 1.0 ,服务器是我用java语言自己编写的 ...

  9. linux安装oracle 11g乱码,Linux下安装Oracle11g中文乱码,DISPLAY未通过

    Linux下安装Oracle11g中文乱码 Linux下安装Oracle11g,安装界面乱码问题解决方法: 解决 1.下载中文字体 2.进入刚解压的database/stage/Components/ ...

最新文章

  1. 实验进行中:.NET WebAssembly支持
  2. 有限元基础: Jacobian 矩阵和高斯积分
  3. IDEA设置自定义代码模板
  4. 看了就会的 Node.js 三大基础模块常用 API
  5. 分布式ID生成的9种方法,特好用!
  6. ios html字符转义字符串,iOS HTML特殊字符转译
  7. python版本年份_Python问题:至今的年份和年份?
  8. Mysql开启远程连接方法
  9. nhibernate配置教程
  10. 关于人工智能你需要了解的事
  11. 使用telnet 方式管理交换机
  12. Ffmpeg视频压缩
  13. Visio画坐标系步骤
  14. 再次深入分析不可重入函数---请小心使用localtime函数
  15. 【邀请函】2018年医院绩效改革方案构建与落地实践成果分享会
  16. EfficientNet B0 训练 Standford 汽车图片分类(对比ResNet34)
  17. 游戏中找CALL的万能方法
  18. 第五章第三十五题(加法)(Summation)
  19. java基于springboot足球联赛管理系统
  20. 什么是扭矩?如何做好扭矩?

热门文章

  1. SpringBoot 2.x 集成 Redis
  2. java split函数报错
  3. 03:计算矩阵边缘元素之和
  4. 开发外包注意事项——iOS APP的开发
  5. WinForm 布局控件“WeifenLuo.WinFormsUI.Docking“的使用
  6. mysql pdo 读取字段名_PHP使用PDO从mysql读取大量数据处理详解
  7. linux ssh和scp,Linux SSH 与 SCP命令简述
  8. 带圆圈大小的散点图_Python数据可视化,Matplotlib绘制“散点图”的两种方法!...
  9. Android打开jsp页面,如何确定是通过jsp页面上的Android设备还是IOS设备访问网页
  10. 多线程内存泄漏_内存泄漏的场景和解决办法