以下過程用8位的有符號char表示資料。
1. 計算機為什麼用補碼儲存整數
- 加法執行
計算機是按照二進位制儲存的,並且計算機只會做加法,不會減法。
首先看下加法,例如1+1=2
0000 0001
0000 0001
——————————
0000 0010
如果是1-1呢,因為計算機不會減法,會轉換為1+(-1)。這就涉及到-1怎麼表示了?如果用1000 0001表示-1進行如下計算
0000 0001
1000 0001
—————————
1000 0010 這個結果就表示-2,正確結果應該是0,說明這種表示方式不行。
- 引入補碼
針對該問題,計算機的前輩們想到用補碼的形式表示整數(記憶體中儲存也是存的補碼),正數的補碼和原碼一樣,負數的補碼的非符號位取反後加1。
按照這個規則,-1用補碼錶示為1000 0001(原碼)——非符號為取反——>1111 1110——加1——>1111 1111.所以1+(-1)的計算過程如下:
0000 0001
1111 1111
——————————
10000 0000 這個結果表示0,正確。
2.-128怎麼表示
大家都知道char的取值範圍是-128~127,但是-128怎麼表示呢?我們按照上面的補碼規則推算一下:
1 1000 0000(用9位表示的原碼)——非符號位取反——>1 0111 1111——加1——>1 1000 0000(補碼)
由上可知,原碼 1 1000 0000對應的補碼還是自身。截斷溢位的最高位後是1000 0000。
如果只8位的1000 0000,有人可能會認為是表示-0,實際是已經用0000 0000表示0了,1000 0000再表示0就重複了,那就約定表示-128,而且這樣表示不會引入錯誤(至於之前的大佬怎麼想出來的,我暫時還不清楚),例如-128+64,計算過程如下:
1000 0000
0100 0000
—————————
1100 0000 (補碼形式)——減1——>1011 1111——非符號位取反——>1100 0000(原碼形式,表示-64)
3.在Linux環境下,如何用gdb檢視某個變數在記憶體中是按照補碼形式儲存的呢
如上圖所示:
先用命令 p 檢視變數val的記憶體地址,為0xffff1423.
再用命令 x 檢視記憶體儲存情況。
x /4xb 0xffff1423
4:表示檢視4個位元組的記憶體.
x:表示記憶體資料顯示的格式,和C語言中的printf保持一致.
b:表示記憶體單位大小 ,b:1個位元組,h:Halfwords(2個位元組),w:Words(4個位元組).
如上圖,變數val在記憶體中儲存為"ff ff ff f6" 確實是-10的補碼形式.