偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

徹底解決QT中文碼亂問(wèn)題

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

[[438437]]

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

前言

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

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

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

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

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

在開(kāi)始前,我們先來(lái)羅列一下遇到的幾種情況:

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

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

一、字符編碼

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

1.1 ASCII編碼

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

ASCII編碼表

1.2 中文編碼

計(jì)算機(jī)剛開(kāi)始被發(fā)明的時(shí)候,只有ASCII編碼。也就是說(shuō)只有英文,那我們?cè)趺崔k呢?沒(méi)有人幫我們做,那只有自己來(lái)了,在1980年,國(guó)家標(biāo)準(zhǔn)總局發(fā)布了GB2312,其實(shí)就是一張中文的編碼對(duì)照表。這也不是很復(fù)雜的東西,因?yàn)閱蝹€(gè)字節(jié)只有256種可能,也就是說(shuō),最多只能表示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è)字符來(lái)決定是哪個(gè)中文字符了。

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

1.3 Unicode編碼

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

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

最終,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)行編碼。對(duì)于使用英語(yǔ)的國(guó)家來(lái)說(shuō),原來(lái)采用的是ASCII編碼,那么所有的文件大小都會(huì)變成原來(lái)的2倍。這個(gè)浪費(fèi)太大了,于是UTF-8就出現(xiàn)了。

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

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

 1110 0100

 1011 1000

 1010 1101

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

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

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

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

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

2.2 ANSI編碼

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

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

 

[[438442]]

[[438443]]

[[438444]]

[[438445]]

三、一勞永逸地消除亂碼

在解決問(wèn)題前,我們?cè)偕晕⒘私庖恍┍尘爸R(shí),小伙伴們不要著急?。?/p>

3.1 UTF-8和UTF-8-BOM

UTF-8都?jí)驈?fù)雜了,還來(lái)個(gè)UTF-8-BOM??

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

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

上圖,我們?cè)谟浭卤局袑懭?ldquo;中文”,然后,以u(píng)tf-8保存。

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

但是,如果再次打開(kāi),還會(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)通”,保存,再打開(kāi)。你是不是看到了微軟對(duì)聯(lián)通滿滿的惡意?哈哈O(∩_∩)O哈哈~

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

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

3.2 編輯器和編譯器對(duì)文件的處理

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

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

VS的編譯器經(jīng)常認(rèn)錯(cuò)utf-8文件為ANSI文件,曾經(jīng)有小伙伴把這個(gè)問(wèn)題,向微軟提交了這個(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.

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

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

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

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

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

3.3 Qt中QString對(duì)中文的處理

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

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

QString str1("中文");

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

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

3.4 解決方案

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

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

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

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

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

char * str = "中文中";

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

e4 b8 ad e6 96 87 e4 b8 ad

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

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

 char * str = "中文中 ";

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

e4 b8 ad e6 96 87 e4 b8 ad 20

剛好是10個(gè)字節(jié),所以,編譯沒(méi)有報(bào)錯(cuò),但是在編譯器編譯的過(guò)程中,是按照GBK進(jìn)行解析的,到解析到最后,遇到ad 20,發(fā)現(xiàn)找不到GBK中對(duì)應(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í),文章的開(kāi)頭提到的第1種沒(méi)有問(wèn)題的情況,很有可能,程序比較簡(jiǎn)單,而中文字符出現(xiàn)的個(gè)數(shù)剛好是偶數(shù)。真是人品大爆發(fā),在發(fā)生2次誤解的情況下,得到了正確的結(jié)果。O(∩_∩)O哈哈~

[[438447]]

[[438448]]

[[438449]]

[[438450]]

四、總結(jié)

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

 

責(zé)任編輯:龐桂玉 來(lái)源: 良許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窗體繼承

2025-06-17 06:40:45

DockerDocker鏡像

2010-01-14 10:19:05

2025-08-07 02:45:00

2009-12-25 09:39:08

ADSL MODEM

2009-11-24 19:50:10

2022-10-08 23:55:58

iOS蘋果開(kāi)發(fā)

2011-06-29 18:02:58

Qt 中文 翻譯

2011-06-13 16:16:32

Qt 中文問(wèn)題

2009-12-21 17:20:19

2022-05-31 09:01:13

GitHub工具安全

2009-12-04 16:25:24

2024-11-04 10:05:00

AI模型

2009-12-03 16:54:04

無(wú)線寬帶路由器
點(diǎn)贊
收藏

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