此係列爲讀<深入理解計算機系統>的筆記,如有理解錯誤,望請指正.
第二章 信息的表示和處理
現代計算機存儲和處理信息是以二進制信號表示,這些微不足道的二進制數字,或稱爲位(bit)奠定了數字革命的基礎
2.1 信息存儲
大多數計算機使用的8位的塊,或者字節(byte),作爲最小的可尋址的存儲器單位,而不是存儲器中訪問單獨的位.
機器級程序將存儲器視爲一個非常大的字節數組,稱爲虛擬存儲器.
存儲器的每個字節都由一個唯一的數字來標識,稱爲它的地址,所有可能地址的集合稱爲虛擬地址空間.
虛擬地址空間只是一個展現給機器級程序的概念性映像.
2.1.1 十六進制表示法
一個字節由8位組成.二進制表示法中值域是00000000(下角標2)~11111111(下角標2)十六進制使用數字’0’~’9’以及字符’A’~’F’來表示16個可能的值.一個字節的值域爲00(下角標16)~FF(下角標16).
2.1.2 字
每臺計算機都有一個字長,指明整數和指針數據標稱大小.虛擬地址是以一個字來編碼的,字長決定的最重要的系統參數就是虛擬地址空間的最大大小,大多數計算機的字長都是32位.64位機器正在普遍起來.
2.1.3 數據大小
計算機和編譯器支持多種不同方式的編碼數字格式.如:整數,浮點數以及其他長度的數字.
2.1.4 尋址和字節順序
對於跨越多字節的程序對象,我們必須建立兩個規則:
- 1,對象的地址是什麼
- 2,如何排列這些字節
在幾乎所有的機器上,多字節對象都被存儲爲連續的字節序列,對象地址爲所使用字節中最小的地址.
2.1.5 表示字符串
每個字符都由某個標準編碼來表示,最常見的是ASCII字符碼.
ASCII字符集適合編碼英文文檔.
基本編碼也稱爲Unicode的”統一字符集”,使用32位來表示字符.
Java編程語言使用Unicode來表示字符串.對於C語言也有支持Unicode的程序庫.
2.1.6 表示代碼
不同的機器類型使用不同的且不兼容的指令和編碼方式.
即使處理器一樣,運行的系統不一樣,也有不同的處理編碼的規則,因此二進制代碼是不兼容的.
二進制代碼很少能在不同機器和操作系統組合之間移植.
計算機系統的一個基本概念,就是從機器角度來看,程序僅僅只是字節序列.機器沒有關於初始源程序的任何信息,除了可能有些用來幫助調試的輔助表以外.
2.1.7 布爾代數簡介
二進制值是計算機編碼、存儲和操作的核心,所以圍繞數值0和1的研究已經演化出了豐富的數學知識體系.
最簡單的布爾代數是在二元集合{0,1}基礎上的定義.
2.1.8 C語言中的位級運算
C語言一個很有用的特性就是它支持按位布爾運算.
C語言所使用:|就是OR(或),&就是AND(與),~就是NOT(取反),^就是EXCLUSIVE~OR(異或).
確定一個位級表達式的結果的最好的方式,就是將十六進制的參數擴展成二進制表示並執行二進制運算,然後轉回十六進制.
2.1.9 C語言中的邏輯運算.
C語言還提供了一組邏輯運算符||(OR)、&&(AND)和!(NOT)
2.1.10 C語言中的移位運算
C語言還提供了一組移位運算,以便向左或向右移動位模式.右移運算X>>K,左移運算X<
2.2 整數表示
我們描述用位來編碼證書的兩種不同的方式:
一種只能表示非負數,另一種能夠表示負數、零和正數.
2.2.1 整型數據類型
C語言支持多種整型數據類型—–表示有限範圍的整數.
每種類型都能用關鍵字來指定大小,如:char、short、long或者long long.
不同大小的分配的字節數會根據機器的字長和編譯器有所不同.
根據字節分配,不同的大小所能表示的值的範圍是不同的.
2.2.2 無符號數的編碼
無符號的二進制表示有一個很重要的屬性,就是每個介於0~2^w-1之間的數都有唯一一個w位的編碼值.
2.2.3 補碼編碼
最常見的有符號數的計算機表示方式就是補碼形式.
在這個定義中,將字的最高有效位解釋爲負權.
每個介於-2^(w-1)和2^w-1之間的整數都有一個唯一長度爲w的位向量二進制表示.
2.2.4 有符號數和無符號數之間的轉換
C語言允許在各種不同的數字數據類型之間做強制類型轉換.
2.2.5 C語言中的有符號數與無符號數
C語言支持所有整型數據類型的有符號和無符號運算.
C語言標註沒有指定有符號數要採用某種表示,但是幾乎所有的機器都使用補碼.
C語言允許無符號數和有符號數之間的轉換.轉換的原則是底層的位表示保持不變.
2.2.6 擴展一個數字的位表示
一種常見的運算是在不同字長的整數之間轉換,同時又保持數值不變.
2.2.7 截斷數字
假設我們不用額外的位來擴展一個數值,而是減少表示一個數字的位數.
在一臺典型32位機器上,當把int X強制類型轉換爲short時,我們就將32位的int截斷爲16位的short int.
這個16位的位模式就是-12345的補碼錶示.
當把它強制轉換回int時,符號擴展把高16位設置爲1,從而生成-12345的32位補碼錶示.
2.2.8 關於有符號與無符號的建議
有符號數和無符號數的隱式強制類型轉換導致某些非直觀的行爲
這些非直觀的特性經常導致程序錯誤,並且隱式強制類型轉換細微差別的錯誤呀不易察覺.
強制類型轉換在代碼沒有明確指示下發生,程序員經常忽視了它的影響.
2.3 整數運算
許多剛入門的程序員非常驚奇的發現,兩個正數相加會得出一個負數,並且比較表達式x < y和比較表達式x-y<0會產生不同的結果.這些屬性是由於計算機運算的有限性造成的.理解計算機的細微之處有助於程序員編寫更可靠的代碼.
- 2.3.1 無符號加法
- 2.3.2 補碼加法
- 2.3.3 補碼的非
- 2.3.4 無符號乘法
- 2.3.5 補碼乘法
- 2.3.6 乘以常數
- 2.3.7 除以2的冪
2.3.8 關於整數運算的最後思考
正如我們看到的.計算機執行”整數”運算實際上是一種模運算形式.表示數字的有限字長限制了可能的值的取值範圍.結果運算可能溢出.我們看到,補碼錶示提供了一種既能表示負數也能表示正數的靈活方式,同時使用了與執行無符號算術相同的位級實現,這些運算包括加法、減法、乘法,甚至除法.無論運算數是以無符號形式還是以補碼形式表示的.都有完全一樣或者非常類似的位級行爲.
2.4 浮點數
浮點數表示對有理數進行編碼,它對執行非常大的數字,非常接近於0的數字,以及更普遍地作爲實數運算的近似值的計算,是很有用的.
- 2.4.1 二進制小數
- 2.4.2 IEEE浮點表示
- 2.4.3 數字示列
- 2.4.4 舍入
- 2.4.5 浮點運算
- 2.4.6 C語言中的浮點數
2.5 小結
計算機將信息按位編碼,通常組織成字節序列.用不同的編碼方式表示整數,實數和字符串.不同的計算機模型在編碼數字和多字節數據中的字節排序時使用不同的約定.
C語言的設計可以包容多種不同字長和數字編碼的實現.雖然高端機器逐漸開始使用64位字長,但是目前大多數機器仍使用32位字長.大多數機器對整數使用補碼編碼,而對浮點數使用IEEE浮點編碼.在位級上理解這些編碼,並且理解算術運算的數學特性,對於想使編寫程序能在全部數值範圍上正確運算的程序員來說,是很重要的.
在相同長度的無符號和有符號整數之間進行強制類型轉換時,大多數C語言實現遵循的原則是底層位模式不變.
由於編碼的長度有限,與傳統整數和實數運算相比,計算機運算具有完全不同的屬性.當超出表示範圍時,有限長度能夠引起數值溢出.當浮點數非常接近於0.0,從而轉換成零時,也會下溢.
必須非常小心地使用浮點運算,因爲浮點運算只有有限的範圍和精度,而且不遵守普遍的算術屬性,比如結合性.
個人記錄:
由於本章涉及大量的數學公式和算法,無法一一進行記錄,並且有很多似懂非懂的知識點,但是在學習和記錄的過程中,還是學到了很多知識,當記錄時又回重新看一遍,重新思考一遍,每次看都會有不同的理解,會一點點的加深印象,以前不太懂的,也在記錄的過程中重新思考.因爲很多知識並沒有深入的研究和學習過,讀起來還是有些吃力,但學習的過程總歸是痛並快樂着的.記錄下來,沒事的時候可以翻翻,也可以在哪裏懂了之後再次加深印象.
學習的過程很枯燥,但是也很快樂.個人能力有限,如有理解錯誤,請君指正,不勝感謝…