前面我們介紹了《深入理解計算機系統》第一章的內容----計算機系統漫游。包括簡單介紹了 Hello World 程序在計算機中是如何運行的,存儲設備的層次結構以及操作系統的抽象概念。第一章的內容只是對很多概念有個簡單了解,所以還是不懂的話也不要緊,后面都會對這些概念進行深入的探究。而這一章我們將介紹《深入理解計算機系統》第二章----信息的表示和處理。
程序=數據結構+算法,所以了解數據結構對我們寫程序是非常有幫助的,這一章會詳細探討計算機數據的存儲和表示,其中也會有大量的公式推導。不要害怕看不懂,LZ 有很多也是第一遍看不懂,但是后面慢慢推導,多看幾遍就看懂了,相信只要具備了高中代數知識的都能看懂。而且了解這些知識之后,你會發現你以前的程序代碼很多都不嚴謹,仿佛在你程序生涯中重新打開了一扇窗。
那么多的不說了,這篇博客我們就來看看計算機中信息的存儲和表示。
1、信息的存儲
什么是信息?信息是客觀事物屬性的反映,是經過加工處理並對人類客觀行為產生影響的數據表現形式。
那么我們這里也要提一下什么是數據,數據是反應客觀事物屬性的記錄,是信息的具體表現形式。任何事物的屬性都是通過數據來表示的,數據經過加工處理后成為信息,而信息必須通過數據才能傳播,才能對人類產生影響。
例如,數據2、4、6、8、10、12是一組數據,其本身是沒有意義的,但對它進行分析后,就可得到一組等差數列,從而很清晰的得到后面的數字。這便對這組數據賦予了意義,稱為信息,是有用的數據。
計算機內所有的信息均以二進制的形式表示,也就是由值0和值1組成的序列。大多數計算機使用8位的塊,或者說字節("位(bit)"是電子計算機中最小的數據單位,每一位的狀態只能是0或1。8個二進制位構成1個"字節(Byte)"),來作為最小的可尋址的存儲器單位,而不是在存儲器中訪問單獨的位。
也就是說我們訪問計算機最小的單位是八個位構成的字節,而不是值0或值1的單個位。
程序會將存儲器視為一個非常大的字節數組,稱為虛擬存儲器(virtual memory)。存儲器的每一個字節都由唯一的數字來標識,也就是我們說的地址(address),所有可能地址的集合稱為虛擬地址空間(virtual address space)
比如 C 語言中的一個指針的值,無論它是指向一個整數、一個結構或是某個其他程序的對象,都是某個存儲塊的第一個字節的虛擬地址。
編譯器和系統運行時是如何將存儲器空間划分為更可管理的單元,用來存放不同的程序對象。這個后面會詳細介紹。
2、十六進制表示法
一個字節由 8 位組成。在二進制表示法中,它的值域為 00000000——11111111;如果用十進制表示就是0——255。這兩種表示法用來描述計算機中的位模式(計算機中所有二進制的0、1代碼所組成的數字串)來說都不是很方便。二進制表示法太冗長,而十進制表示法與位模式的互相轉化又比較麻煩。這時候 十六進制數產生了,十六進制使用數字‘0’~‘9’,以及字符 ‘A’~'F’來表示16個可能的值。一般是 0x 或者 0X 開頭。規則是:借一當十六,逢十六進一。
比如十進制數 175,我們用十六進制表示為 0xAF。
十六進制與十進制、二進制之間的互相轉換這里就不詳細講解了,相信了解編程的對這個應該是很熟悉了。
3、字
計算機進行數據處理時,一次存取、加工和傳送的數據長度稱為字(word),一個字通常由一個或多個(一般是字節的整數位)字節構成,字的位數叫做字長(word size),每台計算機都有一個字長,用來指明整數和指針數據的標稱大小(nominal size)。由於虛擬地址空間中的地址就是使用一個字來編碼的,因此字長決定了系統的虛擬地址空間的最大大小。
通俗來講:字長是CPU的主要技術指標之一,指的是CPU一次能並行處理的二進制位數,字長總是8的整數倍,通常PC機的字長為16位(早期),32位,64位。
比如:LZ 打開命令提示符,然后輸入 systeminfo,可以看到處理器的位數是 64 位
也就是說 LZ 的電腦字長為 64 位,不過現在基本上 CPU 都是64 位的,但是為了發揮64位字長的優勢,我們必須與64位軟件相輔相成,比如你得安裝64位操作系統,否則的話,在32位軟件系統中64位字長的CPU只能當32位用。
4、數據大小
計算機和編譯器支持多種不同方式編碼的數字格式,比如整數和浮點數,以及其它長度的數字。而且由於計算機位數的不同,會造成計算機在各種數據類型分配的字節數不一樣。下圖是 C 語言在 32位機器和64 位機器上各種類型所分配的字節數對比。
我們可以看出,對於長整形( long int)以及字符指針類型(char *)來說,在32位和64位系統下的字節數是不同的。所以在編程時,考慮到系統的移植性,這是我們必須要考慮的。
注意:對於指針類型,由於指針指向的是地址,而虛擬空間的大小是由字長決定的。所以在32位系統下,指針大小為4個字節,在64位系統下,指針大小為8個字節。
5、尋址和字節順序
對於跨越多個字節的程序對象(程序對象指指令、數據或者控制信息等,是程序當中對象的統稱)來說,我們需要制定兩個規則:
①、這個對象的地址是什么?
②、在存儲器中如何排列這些字節?
在幾乎所有的機器上,多字節對象都被存儲為連續的字節序列,對象的地址為所使用字節中最小的地址。
比如:假設一個類型為 int 的變量 x 地址為 0x100,也就是說地址表達式 &x 的值是 0x100,那么,x 的 4 個字節將被存儲在存儲器的 0x100,0x101,0x102,0x103的位置。
第一個規則解決了,那么第二個規則如何排列呢?采用如下兩種方式:
小端法:按照從最低有效字節到最高有效字節的順序存儲對象,也就是最低有效字節在最前面。
大端法:和小端法相反。是按照從最高有效字節到最低有效字節的順序存儲對象,也就是最高有效字節在最前面。
回到上面的變量 x,如果假設 x 的低位字節值到高位字節值分別為 67,45,23,01。那么用大端法和小端法表示分別如下:
由於排列字節的方式有兩種,那么這就產生問題了。比如當小端法機器產生的數據被發送到大端法機器或者反方向發送的時候就會發現,接收程序里的字節成了反序。
為了避免這種情況,網絡應用程序的代碼編寫必須遵循已建立的關於字節順序的規則,以確保發送方機器將它的內部表示轉換成網絡標准,而接收方機器則將網絡標准轉換為它的內部表示。
6、數據類型
上面我們在講解第4小點數據大小時,我們給出了 C 語言中很多的數據類型。那么數據類型到底是什么呢?
程序編碼中,計算機是不認識我們所定義的數據類型的。數據類型的出現是為了把數據分成所需內存大小不同的數據,編程的時候需要用大數據的時候才定義大數據類型,然后編譯器編譯標記需要申請大內存,就可以充分利用內存。 例如大胖子必須睡雙人床,就給他雙人床,瘦的人單人床就夠了。
那么我們可以根據上面的尋址和字節順序得出,計算機在解釋一個數據類型的值時主要有四個因素:位排列規則(大端或者小端)、起始位置、數據類型的字節數、數據類型的解釋方式。
對於特定的系統來說,前兩種因素都是特定的,而對於后兩種因素的改變,則可以改變一個數據類型的值的最終計算結果,這就是強制類型轉換。對於大部分高級程序設計語言來講,都提供了強制類型轉換。強制類型轉換有時候會讓結果變的讓人難以預料,所以我們需要慎用。
7、字符串的表示
在計算機中,對非數值的文字和其他符號進行處理時,要對文字和符號進行數字化,即用二進制編碼來表示文字和符號。其中西文字符最常用到的編碼方案有ASCII編碼和EBCDIC編碼。對於漢字,我國也制定的相應的編碼方案,比如 GBK,GB2312等。
比如字符 ‘a’ 的 ASCII 碼十進制值為 97,在計算機中用二進制表示就是 01100001
8、代碼的表示
程序其實就是一個二進制序列的簡單描述,編譯器會幫我們將其翻譯成對應的機器所認識的二進制序列。
9、總結
本篇博客主要講解了信息在計算機中是如何存儲和表示的,需要注意的是我們訪問計算機最小的單位是八個位構成的字節,而不是值0或值1的單個位。下一篇博客我們將介紹布爾代數以及C語言中的位運算。