天天看點

重學計算機組成原理(十)- "燙燙燙"亂碼的由來(下)2 字元串的表示,從編碼到數字3 總結延伸4 推薦閱讀參考

2 字元串的表示,從編碼到數字

不僅數值可以用二進制表示,字元乃至更多的資訊都能用二進制表示

最典型的例子就是字元串(Character String)

最早計算機隻需要使用英文字元,加上數字和一些特殊符号,然後用8位的二進制,就能表示我們日常需要的所有字元了,這個就是我們常常說的ASCII碼(American Standard Code for Information Interchange,美國資訊交換标準代碼)

重學計算機組成原理(十)- "燙燙燙"亂碼的由來(下)2 字元串的表示,從編碼到數字3 總結延伸4 推薦閱讀參考

ASCII碼就好比一個字典,用8位二進制中的128個不同的數,映射到128個不同的字元裡

比如,小寫字母a在ASCII裡面,就是第97個,也就是二進制的0110 0001,對應的十六進制表示就是 61。而大寫字母 A,就是第65個,也就是二進制的0100 0001,對應的十六進制表示就是41。

在ASCII碼裡面,數字9不再像整數表示法裡一樣,用0000 1001來表示,而是用0011 1001 來表示。字元串15也不是用0000 1111 這8位來表示,而是變成兩個字元1和5連續放在一起,也就是 0011 0001 和 0011 0101,需要用兩個8位來表示。

我們可以看到,最大的32位整數,就是2147483647。如果用整數表示法,隻需要32位就能表示了。但是如果用字元串來表示,一共有10個字元,每個字元用8位的話,需要整整80位。比起整數表示法,要多占很多空間。

這也是為什麼,很多時候我們在存儲資料的時候,要采用二進制序列化這樣的方式,而不是簡單地把資料通過CSV或者JSON,這樣的文本格式存儲來進行序列化。不管是整數也好,浮點數也好,采用二進制序列化會比存儲文本省下不少空間。

ASCII碼隻表示了128個字元,一開始倒也堪用,畢竟計算機是在美國發明的

然而随着越來越多的不同國家的人都用上了計算機,想要表示譬如中文這樣的文字,128個字元顯然是不太夠用的。于是,計算機工程師們開始各顯神通,給自己國家的語言建立了對應的字元集(Charset)和字元編碼(Character Encoding)

字元集

表示的可以是字元的一個集合

比如“中文”就是一個字元集,不過這樣描述一個字元集并不準确

想要更精确一點,我們可以說,“第一版《新華字典》裡面出現的所有漢字”,這是一個字元集。這樣,我們才能明确知道,一個字元在不在這個集合裡面

比如,我們日常說的Unicode,其實就是一個字元集,包含了150種語言的14萬個不同的字元。

字元編碼

則是對于字元集裡的這些字元,怎麼一一用二進制表示出來的一個字典

我們上面說的Unicode,就可以用UTF-8、UTF-16,乃至UTF-32來進行編碼,存儲成二進制。是以,有了Unicode,其實我們可以用不止UTF-8一種編碼形式,我們也可以自己發明一套 GT-32 編碼,比如就叫作Geek Time 32好了。隻要别人知道這套編碼規則,就可以正常傳輸、顯示這段代碼。

重學計算機組成原理(十)- "燙燙燙"亂碼的由來(下)2 字元串的表示,從編碼到數字3 總結延伸4 推薦閱讀參考

同樣的文本,采用不同的編碼存儲下來。如果另外一個程式,用一種不同的編碼方式來進行解碼和展示,就會出現亂碼。這就好像兩個軍隊用密語通信,如果用錯了密碼本,那看到的消息就會不知所雲。在中文世界裡,最典型的就是“手持兩把锟斤拷,口中疾呼燙燙燙”的典故。

沒有經驗的同學,在看到程式輸出“燙燙燙”的時候,以為是程式讓CPU過熱發出報警,于是嘗試給CPU降頻來解決問題。

既然今天要徹底搞清楚編碼知識,我們就來弄清楚“锟斤拷”和“燙燙燙”的來龍去脈。

“锟斤拷”的來源

如果我們想要用Unicode編碼記錄一些文本,特别是一些遺留的老字元集内的文本,但是這些字元在Unicode中可能并不存在。于是,Unicode會統一把這些字元記錄為U+FFFD這個編碼

如果用UTF-8的格式存儲下來,就是\xef\xbf\xbd。如果連續兩個這樣的字元放在一起,\xef\xbf\xbd\xef\xbf\xbd,這個時候,如果程式把這個字元,用GB2312的方式進行decode,就會變成“锟斤拷”。這就好比我們用GB2312這本密碼本,去解密别人用UTF-8加密的資訊,自然沒辦法讀出有用的資訊。

而“燙燙燙”,則是因為如果你用了Visual Studio的調試器,預設使用MBCS字元集

“燙”在裡面是由0xCCCC來表示的,而0xCC又恰好是未初始化的記憶體的指派。于是,在讀到沒有指派的記憶體位址或者變量的時候,電腦就開始大叫“燙燙燙”了。

3 總結延伸

到這裡,相信你發現,我們可以用二進制編碼的方式,表示任意的資訊。隻要建立起字元集和字元編碼,并且得到大家的認同,我們就可以在計算機裡面表示這樣的資訊了。是以說,如果你有心,要發明一門自己的克林貢語并不是什麼難事。

不過,光是明白怎麼把數值和字元在邏輯層面用二進制表示是不夠的。我們在計算機組成裡面,關心的不隻是數值和字元的邏輯表示,更要弄明白,在硬體層面,這些數值和我們一直提的半導體和電路有什麼關系。下一講,我就會為你揭開神秘的面紗。我會從時鐘和D觸發器講起,最終讓你明白,計算機裡的加法,是如何通過電路來實作的。

4 推薦閱讀

《編碼:隐匿在計算機軟硬體背後的語言》

重學計算機組成原理(十)- "燙燙燙"亂碼的由來(下)2 字元串的表示,從編碼到數字3 總結延伸4 推薦閱讀參考
  • 從電報機到計算機,這本書講述了很多計算裝置的曆史故事,當然,也包含了二進制及其背後對應的電路原理。

參考

  • 深入淺出計算機組成原理