手持兩把錕斤拷,口中疾呼燙燙燙。腳踏千朵屯屯屯,笑看萬物鍩鍩鍩。

——程序員間流傳的比較經典的段子。

想必很多剛剛學習編程的萌新也像我一樣,信心滿滿地在Visual Studio中按下ctrl+F5後,行雲流水般地輸入測試數據,結果……卻是燙燙燙鋪滿屏幕。造成這個現象的原因往往是溢出或者數組的越界訪問,導致訪問到了一些未初始化的內存單元,於是便出現了和預期結果不同的燙燙燙。

在學習數組或者字元數組形式的字元串時由於種種原因回出現越界訪問,而許多程序員在學習第一門語言的時候或多或少都出現了這種問題,所以各位腦洞奇大無比的程序員創造出了一系列「燙燙燙」的衍生段子。

但是我們原本的預期結果原本可能不是漢字,而是數字或者字母,為什麼就變成「燙燙燙」了呢?這就涉及到了計算機中的編碼知識。下面就由最基本的二進位編碼開始沿著編碼的發展過程瞭解一下其中的編碼原理。


一、二進位編碼和ASCII編碼

這個部分就是老生常談了:計算機本質上由門電路組成,只有通斷兩種狀態,所以所謂編碼就是要給信息或者數據賦予獨一無二的二進位代碼。

而世界上第一臺電子計算機又是上世紀四十年代美國人發明的,所以英文字母和一些英文符號於1967年被安排成了第一批被編碼能夠在電子計算機的屏幕上顯示的字元。因為一開始要編碼的字元並沒有多少,一些不可見的控制字元和可見的字元加一起纔有128個,雖然這是2的7次方,僅僅需要7位久就能完成這些字元的編碼工作。但是由於一般計算機內存的定址方式為2的偶數次方較為方便,於是人們用一位元組(8位)的低7位來編碼這些字元,最高位為0,而這128個字元被稱為標準ASCII碼(ASCII的全稱為American Standard Code for Information Interchange,直譯為:美國信息交換標準代碼),或者叫做基礎ASCII碼。

有好事者問,為什麼叫做標準ASCII碼呢?難道像三X殺一樣還有標準包和擴展包之分?

欸,還真別說,真叫你給說中了。後來又有一部分字元需要編碼,在1981年人們又湊了128個字元,最高位為1,利用一位元組剩下的7位來編碼這128個字元。這樣一來新的編碼方式便兼容了之前的標準ASCII,使得之前用便準ASCII編碼的數據還可以繼續在計算機屏幕上正常顯示。而這部分新的128個字元被對應地稱為擴展ASCII碼。

附:常用字元ASCII碼記憶規律(首個字元)

空格 0x20 數字 0x30 大寫字母 0x41 小寫字母 0x61

二、JIS基本漢字

隨著世界各國經濟的發展,越來越多的人能接觸到電子計算機,於是便有了制定其他語言編碼的需求。日本作為上個世紀使用漢字的國家中科技發展水平最高的國家,由於日語的表達中也會出現一些漢字,不可避免地面對了將漢字編碼以二進位的形式儲存到計算機中,然後再顯示到屏幕上的問題。

1978年,日本工業規格協會制定了JIS C 6226,即 7ビット及び8ビットの2バイト情報交換用符號化漢字集合(直譯為:七位元及八位元之雙位元組資訊交換用符號化漢字集,簡稱JIS基本漢字)。這也是全世界最早的漢字編碼字符集。

JIS基本漢字收錄了6879個圖形字元,包括6355個漢字和524個非漢字圖形符號,採用了行號列號和區位結合的方式定位,共分為94區,而每區編入94個字元(但實際上為了分類方便,並不是每個區都是滿編94個字元)。習慣上稱第一個位元組為高位元組,第二個位元組為低位元組。高位元組表示該字元所在的區,低位元組由行列號確定該字元在區內的位。01區-09區為非漢字圖形字元,16區-84區為漢字。其中主要各區編碼內容如下:

01區-02區 特殊文字共147個字元

03區 阿拉伯數字以及英文字母大小寫共62個字元 04區 平假名共83個字元 05區 片假名共86個字元 06區 希臘字母大小寫共48字元 07區 西里爾字母大小寫共66個字元 08區 製表符共32個字元 16區-47區 一級漢字共2965個字元 48區-84區 二級漢字共3390個字元 85區-94區 私人造字區

註:一級漢字和二級漢字的劃分依據是使用頻率,將使用頻率高的漢字劃分為一級漢字。

有好事者問:為什麼是94個區呢?94也不是2的n次冪的結果啊?

這個問題問得好,很多人剛接觸漢字編碼時都對這個數字一頭霧水。但是其實這個數字也是在儘可能的範圍內取得最大值。還記得前文ASCII中提到的控制字元嗎?ASCII的前32個字元就是控制字元,實際上第128個字元也是控制碼(DEL,刪除),而區位又是從01開始計數,所以128-32-1-1=94。這就選擇94這個看似很欽定,實際上很有人生哲理的數字的原因。


三、GB2312

日本人搶先一步開發並制定了一套完善的漢字編碼規則之後,作為漢字的發源地,我國也緊隨其後,於1981年制定了一套漢字編碼標準。這套編碼標準稱為GB2312,即中華人民共和國國家標準簡體中文字符集,全稱《信息交換用漢字編碼字符集·基本集》,通常簡稱為GB。GB2312為中國大陸地區的強制標準,亦被使用於新加坡。(香港特區、澳門特區以及臺灣省使用的是另一種名為Big5碼的編碼標準)

GB2312收錄了漢字6763個(其中一級漢字3755個,二級漢字3008個),除此之外還收錄了包括英文字母、希臘字母、日文假名、西里爾字母在內的682個字元,共計7445個字元。同JIS基本漢字一樣,GB2312也劃分了94個區,每個區94個位。但二者各個區的內容略有出入:

01區-09區 特殊符號、數字等682個全形字元(全形字元與半形字元的區別為全形字元佔用兩個位元組,而半形字元只佔用一個位元組)

10區-15區 空區,待擴展 16區-55區 一級漢字共3755個字元(按拼音排序) 56區-87區 二級漢字共3008個字元(按部首/筆畫排序) 88區-94區 空區,待擴展

而國標碼和基本ASCII碼衝突,於是把最高位置為1,得到對應的機內碼,簡稱內碼。內碼正是計算機內存單元中真正儲存的編碼。

隨著國內少數民族對計算機的使用需求和GB2312對漢字收錄過少的侷限性,我國於2000年在GB2312的基礎上擴充,制定了GB18030標準。在GB2312的基礎上,增加了4位元組編碼的方式,涵蓋了中文漢字,日文假名,朝鮮諺文以及其他中國少數民族的文字。


四、CJK編碼

為了交流方便,漢字文化圈的中國、日本、朝鮮、韓國希望能一統一的標準處理漢字,於是在國際社會的共同努力下,於1993年正式制定了收錄字元20902個的中日韓統一表意文字,簡稱CJK編碼。其中C代表中文、J代表日文、K代表諺文。經過多年來的不斷修訂,現已收錄包括古籍生僻字、少數民族文字、朝鮮國字(又稱韓國製漢字)、越南喃字和儒字、琉球漢字、人名生僻字以及科技文獻生僻字等在內的87888個字元,並被廣泛使用於中國、日本、朝鮮、韓國、越南、馬來西亞等國。


最後,回到我們開始時的「燙燙燙」。在Visual Studio中,會將未初始化的內存單元的每個位元組賦值為0xCC,而0xCCCC則是漢字「燙」的一種國標內碼。

而在堆中會默認賦值為0xCD,於是同理就出現了「屯屯屯」。

在UTF-16中用於表示編碼標準的標記為0xFFFE,但是變成UTF-8就成了0xEFBBBF。在UTF-8這個編碼標準中,「鍩」為0xEFBB。

而「錕斤拷」則是在GBK(可以理解為GB2312的擴展)和UTF-8編碼之間的轉換中出現的問題。

參考資料以及擴展閱讀:

ASCII - Wikipedia?

en.wikipedia.org圖標Definition of ASCII?

www.merriam-webster.com
圖標
JIS基本漢字簡介?

www.shuiren.org

在線預覽|GB/T 2312-1980?

c.gb688.cn

在線預覽|GB 18030-2005?

c.gb688.cn

CJK的百科條目?

zh.wikipedia.org


推薦閱讀:

相關文章