1. 程式人生 > >深入理解計算機系統第二章學習筆記

深入理解計算機系統第二章學習筆記

1 資訊儲存

計算機字長,指明指標資料的標稱大小。32位機器虛擬地址空間為4GB。64位為16EB。64位機器可以執行32位機器編譯的程式,反過來不行。

C語言各種資料型別位元組長度如下:


定址和位元組順序:多位元組物件在記憶體中的存放方式分為小端法和大端法。例如一個int有4個位元組[x4,x3,x2,x1],x4位最高位,若x4在最前面(低地址)則為大端法,若x1在最前面則為小端法。大多數Intel相容機都只用小端模式(也就是低地址放低位,高地址放高位)。大多數IBM的使用大端。

大小端產生的問題:1)在不同型別的機器之間通過網路傳輸二進位制資料(用協議解決)2)在閱讀表示整數資料的位元組序列時。3)編寫規避正常的型別系統的程式時。

字串表示:字串被編碼為一個以null(‘\0’)字元結尾的字元陣列。每個字元用某個標準編碼來表示,常見的為ASCII字元碼。擴充套件有Unicode,UTF-8,其中UTF-8相容了ASCII碼。

程式碼表示:不同機器的指令編碼是不同的,一般二進位制程式碼是不相容的。

布林運算:~非,&與,|或,^異或,位運算。

邏輯運算:邏輯運算認為所有非0引數表示TRUE,0表示FALSE。對應OR(||)、AND(&&)和NOT(!)。如果第一個引數求值就能確定表示式的結果,那麼邏輯運算子就不會對第二個引數求值。

移位運算:左移,x<<k,丟棄最高的k位,右端補k個零。右移分為邏輯右移和算術右移。邏輯右移在左端補0,算術右移在左端補最高位,在有符號的整數(最高位為1)移位時有區別。編譯器預設為算術右移。當一次移位的k大於數的位數w時,C語言標準是移動k%w。


2 整數表示

無符號整數直接用其二進位制數值表示。

有符號整數用補碼編碼,最高位為符號位,1表示負數,0為非負。負數的補碼為原碼的反碼加1,正數的補碼為本身。補碼錶示的範圍,以4位為例,1000表示最小(-8),最大為0111(7),1111表示-1,0000表示0。

可以看出補碼的範圍是不對稱的,|Tmin|=|Tmax|+1,C語言中檔案<limits.h>定義了一組常量,來限定編譯器執行時整數的範圍,有INT_MAX,INT_MIN,UINT_MAX等。

為了保證程式的相容性,ISO C99標準在檔案stdint.h中引入了整數型別類,定義瞭如int32_t和int64_t這樣恆定長度的整數型別。

在C語言中,允許強制型別轉換,轉換規則是數值可能會變化,位模型不變。例如下面程式碼:

int i = -1;
unsigned int v = (unsigned int)i;
cout<<v;
輸出是4294967295(unsigned int的最大值)。因為-1的補碼錶示為0xFFFFFFFF,看做無符號數則為4294967295。

在執行一個運算時,如果一個運算數為有符號的而另一個為無符號的,C語言會隱式的將有符號的轉為無符號的,並假設這兩個數非負。這在比較大小時會產生問題。


在-1<0U中,-1轉為無符號數為4294967295,其大於0。

將一個無符號數轉換為一個更大的資料型別,直接補零就可以,這叫零擴充套件。將一個有符號數轉換為一個更大的資料型別,補符號位,叫符號擴充套件。


3 整數運算

無符號加法:溢位直接去除高位。

有符號加法:當做無符號數進行加法,溢位直接截斷。

有符號的非:-x=~x+1,即等於按位取反再加1.

有符號數的乘法:x*y=(x的補碼*y的補碼)的補碼

整數乘以常數:用移位和加法以及減小來代替乘法,無論x是無符號的還是有符號的,其計算結果一致。

整數除以常數:思路與乘法一致。有符號整數移位在小於0時會出現問題,當x<0時,x>>k的結果是x/(2^k)的向下取整,例如-12340>>4結果為-772,然而-12340/16應該是-771,這時C語言對其進行修改:

(x<0?x+(1<<k)-1:x)>>k
在x<0的情況下,加上(1<<k)-1的偏置量。


4 浮點數表示(IEEE標準)


符號位s:複數s=1,正數s=0

尾數M:是一個二進位制小數

階碼E:對浮點數加權,權重為2,可以為負數。

將這三個數劃分為三個欄位:以float(32位)為例,s為最高位,30-23(8位)表示階碼E,剩下的22-0表示尾數M。double的E為11位,M為52位。


規格化值:在E不全為0,也不全為1。階碼欄位被解釋為以偏置形式表示的有符號數,表示的值為E=e-(2^(k-1)-1),e為階碼錶示的無符號數值,k為階碼E的位數,float為8。小數字段被解釋為小數值f,尾數定義為M=1+f,例如001表示二進位制數0.001,十進位制為1/8,則M為9/8。

非規格化值:階碼全為0,用來表示0和比較小的數。階碼值E=1-(2^(k-1)-1),階碼值的規則和規格化數不同是因為要使得非規格化數過渡到規格化數時平滑,尾數為M=f。

特殊值:階碼全為1,尾數為0時表示無窮大,其他表示NaN(不是一個數)。

8位浮點格式例子如下,k=4,n=3.

浮點數的舍入:從上述浮點數的表示可以發現只能近似地表示實數運算,因此需要舍入。預設為向偶數舍入法。


在C語言中,有兩種浮點數float和double,舍入方法為向偶數舍入,不能修改舍入方法,在標準方法中不能得到諸如-0,無窮或者NaN的特殊值,在math.h中有這些值。

整數和浮點數之間轉換規則:

int轉float不會溢位,可能被舍入。

double轉float有可能溢位,可能被舍入。

float或double轉int會向0舍入,例如1.9轉為1,-1.9轉為-1.可能溢位。