zoukankan      html  css  js  c++  java
  • VC2010下Qt5的中文乱码问题

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

    我先找一个例子,比如:“中文” 的 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)

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

    输出是: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)

    01 // utf8 with bom
    02 #include <stdio.h>
    03  
    04 int main() {
    05     const char* str = "中文";
    06     for(int i = 0; i < sizeof(str); ++i) {
    07         printf("0x%x ", str[i]&0xFF);
    08     }
    09     return 0;
    10     // Output:
    11     // 0xd6 0xd0 0xce 0xc4
    12 }

    编译没有警告,但是输出有问题: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)

    01 // gbk
    02 #include <stdio.h>
    03  
    04 int main() {
    05     const char* str = "中文";
    06     for(int i = 0; i < sizeof(str); ++i) {
    07         printf("0x%x ", str[i]&0xFF);
    08     }
    09     return 0;
    10     // Output:
    11     // 0xd6 0xd0 0xce 0xc4
    12 }

    没有编译错误,输出也和源代码一致:“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

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

    没有编译错误,输出也和源代码一致:“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

    01 #include <QApplication>
    02   #include <QLabel>
    03  
    04   #if _MSC_VER >= 1600
    05   #pragma execution_character_set("utf-8")
    06   #endif
    07  
    08   int main(int argc, char *argv[])
    09   {
    10       QApplication a(argc, argv);
    11       QLabel label("ąśćółęńżź");
    12       label.show();
    13  
    14       return a.exec();
    15   }

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

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

    01 // Coding: UTF-8(BOM)
    02 #if defined(_MSC_VER) && (_MSC_VER >= 1600)
    03 # pragma execution_character_set("utf-8")
    04 #endif
    05  
    06 #include <QApplication>
    07 #include <QTextCodec>
    08 #include <QLabel>
    09  
    10 int main(int argc, char* argv[])
    11 {
    12     QApplication app(argc, argv);
    13  
    14 #if QT_VERSION < QT_VERSION_CHECK(5,0,0)
    15 #if defined(_MSC_VER) && (_MSC_VER < 1600)
    16     QTextCodec::setCodecForTr(QTextCodec::codecForName("GB18030-0"));
    17 #else
    18     QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
    19 #endif
    20 #endif
    21  
    22     QLabel *label = new QLabel(QObject::tr("你好!"));
    23     label->show();
    24  
    25     return app.exec();
    26 }

    有以下几种类型(源代码必须是带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语言 了 !

    转自开源中国 http://my.oschina.net/chai2010/blog/119833

    我在电脑上找了一个显示中文.ttf文件加到了QtSDk->Simulator->Application->fonts中就可以解决了

  • 相关阅读:
    零散
    修改element的内部样式的两种方式
    在vue-cli项目中使用第三方的js,不是es6格式
    Docker知识
    golang使用grpc
    vue中axios导出文件
    nginx、vue和thinkphp配置
    Mysql的一些问题
    数据库索引失效原因
    golang中使用grpc服务
  • 原文地址:https://www.cnblogs.com/Bonker/p/3453862.html
Copyright © 2011-2022 走看看