自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

徹底解決QT中文碼亂問題

系統(tǒng) Windows
讀完本文,讓你徹底明白Windows下中文亂碼的問題。一勞永逸地解決這個(gè)困擾很多同學(xué)的問題。

[[438437]]

讀完本文,讓你徹底明白Windows下中文亂碼的問題。一勞永逸地解決這個(gè)困擾很多同學(xué)的問題。

前言

在桌面開發(fā)過程中,由于Qt的跨平臺特性,以及更加先進(jìn)的庫封裝。比起MFC,用著不知道要爽多少。Qt獨(dú)創(chuàng)的信號槽機(jī)制,也大大方便了開發(fā)者。可以讓開發(fā)者把更多的精力放在業(yè)務(wù)的邏輯上,而不是語言和庫的各種細(xì)節(jié)上。

可是,在使用的過程中,不少朋友在中文Windows系統(tǒng)下,遇到了亂碼的問題。著實(shí)頭痛,網(wǎng)上搜了一圈,有時(shí)能解決問題,有時(shí)不知道什么原因的情況下又出現(xiàn)了奇怪的問題。同樣的問題在cocos2d-x中也會(huì)出現(xiàn)。

小伙伴們不要灰心,這個(gè)問題連大佬們都頭痛。哈哈~~,請看下面的案例。

上面的問題來自《Cocos2d-x實(shí)戰(zhàn):C++卷》,大佬也很無奈啊。

今天,讓我們來自己剖析一下這個(gè)問題。并最終找到一勞永逸的解決方案。

在開始前,我們先來羅列一下遇到的幾種情況:

  1.  完全正常。(人品大爆發(fā)啊)
  2.  直接亂碼。(哎,時(shí)運(yùn)不濟(jì))
  3.  編譯報(bào)錯(cuò)——C4819,C2001、C2143。(這是犯了什么天條了嗎?) 
  4.  很小心的使用,可能正常。有時(shí)正常,有時(shí)編譯報(bào)錯(cuò),有時(shí)末尾的字是亂碼,前面的正常。(這是什么鬼?。?。

              細(xì)心的小伙伴還總結(jié)出了,偶數(shù)個(gè)中文字符正常,奇數(shù)個(gè)就不行了。后面再加個(gè)英文字符,前面的顯示正常,后面一個(gè)字符亂碼。(我也太難了吧~~~)

一、字符編碼

要徹底理解這個(gè)問題,我們需要從字符編碼說起,小伙伴們稍微有點(diǎn)耐心,這個(gè)其實(shí)很容易理解。字符編碼說白了就是一張對照表。

1.1 ASCII編碼

這個(gè)編碼很容易,就用了一個(gè)字節(jié)進(jìn)行編碼,只能表示英文字符和標(biāo)點(diǎn)符號。這里我就不過多贅述了,百度一下,就有很多文章有詳細(xì)講解。

ASCII編碼表

1.2 中文編碼

計(jì)算機(jī)剛開始被發(fā)明的時(shí)候,只有ASCII編碼。也就是說只有英文,那我們怎么辦呢?沒有人幫我們做,那只有自己來了,在1980年,國家標(biāo)準(zhǔn)總局發(fā)布了GB2312,其實(shí)就是一張中文的編碼對照表。這也不是很復(fù)雜的東西,因?yàn)閱蝹€(gè)字節(jié)只有256種可能,也就是說,最多只能表示256種字符。那么我們就再多用一個(gè)字節(jié)唄,在GB2312中,中文就用2個(gè)字節(jié)進(jìn)行表示。2^16 = 65536,有這么多種可能,編碼漢字綽綽有余了。

當(dāng)然,考慮到兼容ASCII編碼,當(dāng)?shù)谝粋€(gè)字符數(shù)字小于127時(shí),就表示ASCII字符,用一個(gè)字節(jié)就夠了。當(dāng)遇到第一個(gè)字符大于127時(shí),就要結(jié)合第二個(gè)字符來決定是哪個(gè)中文字符了。

剛開始GB2312把6000多個(gè)中文編了進(jìn)去,后來發(fā)現(xiàn)不夠用,又增加了20000多個(gè)字符(包括繁體字),編碼方案名稱改為GBK。再后來,又增加了幾千個(gè)少數(shù)民族字符,編碼方案名稱改為GB18030。到這里,我們就知道GB2312、GBK、GB18030的編碼方式是一脈相承的。為了后面敘述的方便,我們統(tǒng)稱這種為GBK編碼。

1.3 Unicode編碼

在中國使用GBK編碼方案的同時(shí),其他國家和地區(qū)為了使用自己的文字,也紛紛進(jìn)行對自己的語言文字進(jìn)行編碼。造成的結(jié)果就是,不通用!不同語音的操作系統(tǒng)下編輯的文檔,在另一臺不同語音的計(jì)算機(jī)中打開就是亂碼。

隨著全球化的發(fā)展,急需一種統(tǒng)一的編碼方案,來解決這種混亂的局面。

最終,ISO拿出了Unicode編碼,廢棄所有地區(qū)性的編碼方案。重新編碼,所有的字符統(tǒng)一采用2個(gè)字節(jié)進(jìn)行存儲(chǔ)。

GBK編碼方案和Unicode編碼完全不同,這也是亂碼的根源。

[[438438]]

[[438439]]

[[438440]]

[[438441]]

二、文件編碼

2.1 UTF-8編碼

雖然上文中講到ISO將字符進(jìn)行了重新編碼,并發(fā)布了Unicode。每個(gè)字符采用2個(gè)字節(jié),16位進(jìn)行編碼。對于使用英語的國家來說,原來采用的是ASCII編碼,那么所有的文件大小都會(huì)變成原來的2倍。這個(gè)浪費(fèi)太大了,于是UTF-8就出現(xiàn)了。

如果用語言描述UTF-8,有些復(fù)雜。我們來舉個(gè)例子,就很容易明白了。

比如,“中”這個(gè)字,Unicode編碼為:0x4E2D。用二進(jìn)制寫就是(0100-1110-0010-1101),那么用UTF-8,怎么進(jìn)行表示呢?

 1110 0100

 1011 1000

 1010 1101

我來解釋一下,第一個(gè)字節(jié),前面的4位中有連續(xù)的3個(gè)1,表示這個(gè)字符需要有3個(gè)字節(jié)組成。

第二個(gè)字節(jié),前面的2位10,表示上接前面的字節(jié),后面的6位是編碼。

第三個(gè)字節(jié)同第二個(gè)字節(jié),前面的10和后面的編碼。

也就是說,16位的Unicode編碼,被分散到3個(gè)字節(jié)中。

好麻煩啊……的確,遇到中文或其他多字節(jié)編碼的字符是有點(diǎn)麻煩,但是如果是英文字符,直接就用ASCII編碼保存了。直接完全兼容原來的英文文檔,他們就是有這么多的優(yōu)越性,沒辦法,畢竟計(jì)算機(jī)技術(shù)來自他們那兒。

2.2 ANSI編碼

這又是什么編碼?細(xì)心的小伙伴會(huì)發(fā)現(xiàn),你在Windows系統(tǒng)上用記事本編輯完文件,點(diǎn)另存為的時(shí)候,右下角默認(rèn)的編碼就是ANSI。這是Windows為了兼容各種不同的編碼,而這樣做的。

其實(shí),他的做法非常簡單,如果遇到小于127的編碼,就是ASCII編碼,計(jì)算機(jī)都認(rèn)識這個(gè)編碼,對于大于127的編碼,也不用管那么多了,按原樣保存就行了。

 

[[438442]]

[[438443]]

[[438444]]

[[438445]]

三、一勞永逸地消除亂碼

在解決問題前,我們再稍微了解一些背景知識,小伙伴們不要著急??!

3.1 UTF-8和UTF-8-BOM

UTF-8都夠復(fù)雜了,還來個(gè)UTF-8-BOM??

其實(shí),不必?fù)?dān)心,這個(gè)也是非常簡單的。

讓我們先來看個(gè)例子:

上圖,我們在記事本中寫入“中文”,然后,以utf-8保存。

再用notepad++查看存入的內(nèi)容,以十六進(jìn)制顯示。這樣沒有問題。

但是,如果再次打開,還會(huì)正確顯示嗎?記事本怎么知道我們是按utf-8存儲(chǔ)的呢?如果這個(gè)十六進(jìn)制的串,用GBK解碼就是“涓枃”,是不是有點(diǎn)眼熟???我們遇到亂碼的時(shí)候,也經(jīng)常是這種類似的字符。

現(xiàn)在,記事本工作得好好的,但是他有些時(shí)候會(huì)不會(huì)認(rèn)錯(cuò)呢?還真會(huì),用記事本新建一個(gè)文本文件,輸入“聯(lián)通”,保存,再打開。你是不是看到了微軟對聯(lián)通滿滿的惡意?哈哈O(∩_∩)O哈哈~

其實(shí),各種軟件在處理文本文件的時(shí)候,經(jīng)常會(huì)搞錯(cuò)!為了解決這種問題,就引入了utf-8-bom。

做法非常簡單,在utf-8文件的開頭加入ef bb bf 三個(gè)字節(jié),標(biāo)示這是一個(gè)utf-8的文件,告訴軟件,你可別認(rèn)錯(cuò)了。

3.2 編輯器和編譯器對文件的處理

在Qt5 + VS的環(huán)境中,編輯器對于我們的源文件解析的完全沒有問題。

可惜的是VS的編譯器卻不是像我們想像的進(jìn)行工作的。

VS的編譯器經(jīng)常認(rèn)錯(cuò)utf-8文件為ANSI文件,曾經(jīng)有小伙伴把這個(gè)問題,向微軟提交了這個(gè)bug,得到的回復(fù)如下

The compiler when faced with a source file that does not have a BOM the compiler reads ahead a certain distance into the file to see if it can detect any Unicode characters - it specifically looks for UTF-16 and UTF-16BE - if it doesn't find either then it assumes that it has MBCS. I suspect that in this case that in this case it falls back to MBCS and this is what is causing the problem.

翻譯過來,就是當(dāng)編譯器遇到不帶BOM的utf-8文件,會(huì)讀入一部分進(jìn)行判斷是否UTF-16和UTF-16BE,如果不是就按照MBCS方式處理。

它根本就不進(jìn)行utf-8文件的判斷啊,Qt默認(rèn)保存的就是utf-8文件,并且不帶bom。然后,被按照MBCS方式識別,在我們的環(huán)境中,就是按照ANSI方式來處理。

好家伙,,,這么偷懶啊,造成了我們無窮的麻煩……

之前微軟為了這個(gè)問題,還出過在文件開頭加上#pragma execution_character_set("utf-8")的方式,后來也被廢棄了。

到這里,我們明白了,Qt默認(rèn)保存的utf-8文件(不帶bom),被VS的編譯器認(rèn)成了ANSI格式的文件,就是亂碼的根源。

3.3 Qt中QString對中文的處理

Qt中有QString字符串類,使用非常方便。

經(jīng)常我們使用2種常用的方式:

QString str1("中文");

QString str2 = QString::fromLocal8Bit("中文");

需要明確的是第一種方法,也就是QString默認(rèn)構(gòu)造函數(shù),接受的是utf-8字節(jié)序列。第二種方法,接受的是GBK字節(jié)序列。

3.4 解決方案

到這里為止,相信大家對怎么解決中文亂碼的方案已經(jīng)猜出來了。那就是:

在Qt中設(shè)置所有保存的文件都是utf-8-bom格式

在需要使用到中文的地方需要使用QString::fromLocal8Bit()方式。

3.5 編譯出錯(cuò)的問題

到這里,細(xì)心的小伙伴就會(huì)意識到,雖然,我們亂碼的問題得到了解決,但還是不明白前面4種現(xiàn)象中的后兩種是什么情況。這里,我就再給大家解釋一下。

char * str = "中文中";

看上面的代碼,如果我們保存在utf-8文件中,而編譯器把我們的文件認(rèn)成了ANSI格式的,也就是中文部分安裝GBK來解析。我們看“中文中”這三個(gè)字的utf-8編碼

e4 b8 ad e6 96 87 e4 b8 ad

三個(gè)中文字符被編碼成了9個(gè)字節(jié),在編譯器按照GBK編碼進(jìn)行解析,因?yàn)镚BK編碼中,中文字符需要兩個(gè)字節(jié),就把后面的分號就給吞噬掉了。源文件少了個(gè)分號,編譯肯定是通不過的。

還剩最后一個(gè)問題,如果是

 char * str = "中文中 ";

后面多添了一個(gè)空格,引號中的utf編碼為:

e4 b8 ad e6 96 87 e4 b8 ad 20

剛好是10個(gè)字節(jié),所以,編譯沒有報(bào)錯(cuò),但是在編譯器編譯的過程中,是按照GBK進(jìn)行解析的,到解析到最后,遇到ad 20,發(fā)現(xiàn)找不到GBK中對應(yīng)的字符,就把a(bǔ)d 20用3f(?),替代。

QString接收到的字符序列變?yōu)椋?/p>

e4 b8 ad e6 96 87 e4 b8 3f

所以,QString接收到的utf-8序列最后一個(gè)字節(jié)被改掉了,最后一個(gè)字符就顯示出了亂碼了。

其實(shí),文章的開頭提到的第1種沒有問題的情況,很有可能,程序比較簡單,而中文字符出現(xiàn)的個(gè)數(shù)剛好是偶數(shù)。真是人品大爆發(fā),在發(fā)生2次誤解的情況下,得到了正確的結(jié)果。O(∩_∩)O哈哈~

[[438447]]

[[438448]]

[[438449]]

[[438450]]

四、總結(jié)

今天,我們介紹了各種字符編碼,文件存儲(chǔ)編碼,VS編譯器,以及QString對字符的處理。總算理順了出現(xiàn)亂碼的原因。最終的原因,就是Qt默認(rèn)保存為utf-8不帶bom的文件,而VS編譯器對于utf-8文件解析過程中的偷懶,而錯(cuò)認(rèn)為ANSI編碼文件所致。Cocos2d-x中的亂碼,相信小伙伴們也已經(jīng)明白是怎么回事了。 

 

責(zé)任編輯:龐桂玉 來源: 良許Linux
相關(guān)推薦

2009-12-03 18:45:41

2009-11-27 10:31:02

GPRS路由

2023-02-27 08:08:54

Pulsar源碼重復(fù)消費(fèi)

2025-03-03 00:13:50

2010-01-04 15:05:53

2023-11-28 08:36:16

Spring中Body讀取

2010-01-11 18:05:24

VB.NET窗體繼承

2010-01-14 10:19:05

2009-12-25 09:39:08

ADSL MODEM

2009-11-24 19:50:10

2022-10-08 23:55:58

iOS蘋果開發(fā)

2011-06-13 16:16:32

Qt 中文問題

2011-06-29 18:02:58

Qt 中文 翻譯

2009-12-21 17:20:19

2022-05-31 09:01:13

GitHub工具安全

2009-12-03 16:54:04

無線寬帶路由器

2024-11-04 10:05:00

AI模型

2020-09-28 14:41:24

Event Loop

2009-12-04 16:25:24

2021-03-13 21:00:30

電腦PC電腦彈窗廣告
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號