要搞清楚這個問題,先要弄明白編碼。但是編碼問題實在太復雜,這里肯定講不開。
我先找一個例子,比如:“中文” 的 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)
06 |
const char * str = "中文" ; |
07 |
for ( int i = 0 ; i < sizeof(str); ++i) { |
08 |
printf( "0x%x " , str[i]& 0xFF ); |
輸出是: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)
05 |
const char * str = "中文" ; |
06 |
for ( int i = 0 ; i < sizeof(str); ++i) { |
07 |
printf( "0x%x " , str[i]& 0xFF ); |
編譯沒有警告,但是輸出有問題: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)
05 |
const char * str = "中文" ; |
06 |
for ( int i = 0 ; i < sizeof(str); ++i) { |
07 |
printf( "0x%x " , str[i]& 0xFF ); |
沒有編譯錯誤,輸出也和源代碼一致:“0xd6 0xd0 0xce 0xc4”。
因為源文件就是GBK,cl在編譯時GBK轉化為GBK,沒有改變字符串。
只是,現在很多人不想用GBK了(因為只能在中國地區用,不能表示全球字符)。
到這里,可以初步小結一下:
- VC編輯器和VC編譯器是2個概念,VC編輯器支持UTF8並不能表示VC編譯器也支持UTF8
- VC編輯器從2008?開始支持帶BOM的UTF8(不帶BOM的暫時沒戲,因為會本地編碼沖突)
- 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
02 |
#pragma execution_character_set( "utf-8" ) |
07 |
const char * str = "中文" ; |
08 |
for ( int i = 0 ; i < sizeof(str); ++i) { |
09 |
printf( "0x%x " , str[i]& 0xFF ); |
沒有編譯錯誤,輸出也和源代碼一致:“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> |
05 |
#pragma execution_character_set( "utf-8" ) |
08 |
int main( int argc, char *argv[]) |
10 |
QApplication a(argc, argv); |
11 |
QLabel label( "ąśćółęńżź" ); |
If other people can reproduce your problem, you can file a bug.
教完整的解決方案(增加了Qt4/Qt5和非VC環境的判斷):
02 |
# if defined(_MSC_VER) && (_MSC_VER >= 1600 ) |
03 |
# pragma execution_character_set( "utf-8" ) |
06 |
#include <QApplication> |
10 |
int main( int argc, char * argv[]) |
12 |
QApplication app(argc, argv); |
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" )); |
18 |
QTextCodec::setCodecForTr(QTextCodec::codecForName( "UTF-8" )); |
22 |
QLabel *label = new QLabel(QObject::tr( "你好!" )); |
有以下幾種類型(源代碼必須是帶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中就可以解決了