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中就可以解決了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM