要搞清楚這個問題,先要弄明白編碼。但是編碼問題實在太複雜,這裡肯定講不開。
我先找一個例子,比如:“中文” 的 Unicode 碼點/UTF8編碼/GBK 分别是多少。
先去這個網站,輸入 “中文” 查詢對應的 Unicode 碼點/UTF8編碼:
<a href="http://www.mytju.com/classcode/tools/encode_utf8.asp">http://www.mytju.com/classcode/tools/encode_utf8.asp</a>
Unicode的碼點分别是(十進制):中(20013),文(25991)。
對應的UTF8編碼分别(16進制): 中(E4B8AD),文(E69687)。
然後再去下面這個網站,輸入 “中文” 查詢對應的 GBK 編碼:
<a href="http://www.mytju.com/classcode/tools/encode_gb2312.asp">http://www.mytju.com/classcode/tools/encode_gb2312.asp</a>
GBK編碼16進制(GBK内碼)分别是:中(D6D0),文(CEC4)。
現在已經知道了"中文"的UTF8和GBK編碼的具體值。
我們再看看VC2010是怎麼處理的。
<code>01</code>
<code>// utf8 no bom</code>
<code>02</code>
<code>// 檔案中包含不能在目前代碼頁(936)中表示的字元</code>
<code>03</code>
<code>#include <stdio.h></code>
<code>04</code>
<code>05</code>
<code>int</code> <code>main() {</code>
<code>06</code>
<code> </code><code>const</code> <code>char</code><code>* str = </code><code>"中文"</code><code>;</code>
<code>07</code>
<code> </code><code>for</code><code>(</code><code>int</code> <code>i = </code><code>0</code><code>; i < sizeof(str); ++i) {</code>
<code>08</code>
<code> </code><code>printf(</code><code>"0x%x "</code><code>, str[i]&</code><code>0xFF</code><code>);</code>
<code>09</code>
<code> </code><code>}</code>
<code>10</code>
<code> </code><code>return</code> <code>0</code><code>;</code>
<code>11</code>
<code> </code><code>// Output:</code>
<code>12</code>
<code> </code><code>// 0xe4 0xb8 0xad 0xe6</code>
<code>13</code>
<code>}</code>
輸出是: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編譯警告。
<code>// utf8 with bom</code>
<code> </code><code>// 0xd6 0xd0 0xce 0xc4</code>
編譯沒有警告,但是輸出有問題:0xd6 0xd0 0xce 0xc4。
源檔案明明是 UTF8 編碼的格式"0xe4 0xb8 0xad 0xe6”,
怎麼變成了 “0xd6 0xd0 0xce 0xc4” (這個是GBK編碼)?
這就是VC私下幹的好事:它自作聰明的将UTF8源代碼轉換為GBK處理了!
VC為何要做這樣蠢事?
原因是為了相容老的VC版本。
因為以前的VC不能處理UTF8,都是用本地編碼處理的。
<code>// gbk</code>
沒有編譯錯誤,輸出也和源代碼一緻:“0xd6 0xd0 0xce 0xc4”。
因為源檔案就是GBK,cl在編譯時GBK轉化為GBK,沒有改變字元串。
隻是,現在很多人不想用GBK了(因為隻能在中國地區用,不能表示全球字元)。
到這裡,可以初步小結一下:
VC編輯器和VC編譯器是2個概念,VC編輯器支援UTF8并不能表示VC編譯器也支援UTF8
VC編輯器從2008?開始支援帶BOM的UTF8(不帶BOM的暫時沒戲,因為會本地編碼沖突)
VC編譯器從2010開始重要可以支援UTF8了(雖然支援方式很不優雅)
VC2010重要增加了UTF8的編譯支援(<code>#pragma execution_character_set("utf-8")</code>),
具體檢視:
<a href="http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/2f328917-4e99-40be-adfa-35cc17c9cdec">http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/2f328917-4e99-40be-adfa-35cc17c9cdec</a>
<code>// utf8 with bom (VC2010), 這句是重點!</code>
<code>#pragma execution_character_set(</code><code>"utf-8"</code><code>)</code>
<code>14</code>
沒有編譯錯誤,輸出也和源代碼一緻:“0xe4 0xb8 0xad 0xe6”。
UTF8編碼,UTF8輸出。完美!
Qt預設支援 VS2010/MinGW/Gcc 等編譯器,而它們現在都已經真正支援UTF8了。
當然,VS2010 對UTF8的支援會入侵代碼(<code>#pragma execution_character_set("utf-8")</code>)。
看看Qt官方論壇别人是怎麼說的:
<a href="http://qt-project.org/forums/viewthread/17617">http://qt-project.org/forums/viewthread/17617</a>
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 <code>#include <QApplication></code> <code> </code><code>#include <QLabel></code> <code> </code><code>#</code><code>if</code> <code>_MSC_VER >= </code><code>1600</code> <code> </code><code>#pragma execution_character_set(</code><code>"utf-8"</code><code>)</code> <code> </code><code>#endif</code> <code> </code><code>int</code> <code>main(</code><code>int</code> <code>argc, </code><code>char</code> <code>*argv[])</code> <code> </code><code>{</code> <code> </code><code>QApplication a(argc, argv);</code> <code> </code><code>QLabel label(</code><code>"ąśćółęńżź"</code><code>);</code> <code> </code><code>label.show();</code> <code> </code><code>return</code> <code>a.exec();</code> <code>15</code> <code> </code><code>}</code> If other people can reproduce your problem, you can file a bug.
教完整的解決方案(增加了Qt4/Qt5和非VC環境的判斷):
<code>// Coding: UTF-8(BOM)</code>
<code>#</code><code>if</code> <code>defined(_MSC_VER) && (_MSC_VER >= </code><code>1600</code><code>)</code>
<code># pragma execution_character_set(</code><code>"utf-8"</code><code>)</code>
<code>#endif</code>
<code>#include <QTextCodec></code>
<code>#include <QLabel></code>
<code>int</code> <code>main(</code><code>int</code> <code>argc, </code><code>char</code><code>* argv[])</code>
<code>{</code>
<code> </code><code>QApplication app(argc, argv);</code>
<code>#</code><code>if</code> <code>QT_VERSION < QT_VERSION_CHECK(</code><code>5</code><code>,</code><code>0</code><code>,</code><code>0</code><code>)</code>
<code>#</code><code>if</code> <code>defined(_MSC_VER) && (_MSC_VER < </code><code>1600</code><code>)</code>
<code>16</code>
<code> </code><code>QTextCodec::setCodecForTr(QTextCodec::codecForName(</code><code>"GB18030-0"</code><code>));</code>
<code>17</code>
<code>#</code><code>else</code>
<code>18</code>
<code> </code><code>QTextCodec::setCodecForTr(QTextCodec::codecForName(</code><code>"UTF-8"</code><code>));</code>
<code>19</code>
<code>20</code>
<code>21</code>
<code>22</code>
<code> </code><code>QLabel *label = </code><code>new</code> <code>QLabel(QObject::tr(</code><code>"你好!"</code><code>));</code>
<code>23</code>
<code> </code><code>label->show();</code>
<code>24</code>
<code>25</code>
<code> </code><code>return</code> <code>app.exec();</code>
<code>26</code>
有以下幾種類型(源代碼必須是帶BOM的UTF8):
Qt5+/VC2010+: 包含了 <code># pragma execution_character_set("utf-8")</code> 已經支援中文
Qt5/VC2008-: 這個暫時誤解(我還沒找到方法)
Qt4+/VC2008-: 采用以前老的方式, 指定代碼為 “GB18030-0” 編碼
Qt4/Qt5/Linux: 隻要是預設的UTF8環境, 應該都沒問題
其實這個問題不是Qt特有的, 追根溯源還是C/C++和編譯器的問題.
即使是支援UTF16的Java也同樣難逃此問題.
我在電腦上找了一個顯示中文.ttf檔案加到了QtSDk->Simulator->Application->fonts中就可以解決了
QQ:519841366
本頁版權歸作者和部落格園所有,歡迎轉載,但未經作者同意必須保留此段聲明,
且在文章頁面明顯位置給出原文連結,否則保留追究法律責任的權利