關於什麼的原碼、反碼、補碼,不打算在這贅述了
本文從一道筆試題,來看一下整數在內存中的存儲,及運算,由此引發思考,計算機中爲什麼要用補碼?補碼爲什麼要設計成取反加一這種形式?
先上菜
在X86,VC++6.0環境下,有下列程序
#include<stdio.h>
int main()
{
char c;
unsigned char uc;
unsigned short us;
c = 128;
uc = 128;
us = c + uc;
printf(“0x%x”,us);
us = (unsigned char)c + uc;
printf(“0x%x”,us);
us = c + (char)uc;
printf(“0x%x”,us);
return 0;
}
輸出結果爲( )
A) 0x0 0x100 0xff00
B) 0x100 0x100 0xff00
C) 0x100 0x100 0x0
D) 0x0 0x100 0x0
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">據說這是“某爲”在某年招聘時的一道筆試題</span>
c = 128
c的類型爲char 有符號 -128 ~ 127
128 = 1000 0000
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">那麼此時 c的一字節存儲空間中存的內容爲 1000 0000(如果按char類型來解釋這段存儲內容,那麼第一位是符號位,爲1,被解釋爲負數,那麼將被看做補碼,1000 0000 是 -128的補碼,所以按char類型會被解釋爲 -128)</span>
uc = 128;
uc類型爲 unsigned char 無符號 0~255
1000 0000 被存入,按unsigned char 也會被解釋爲 128 這個沒有問題
us= c + uc
兩個一字節長度的類型的數據相加,會先做類型提升,姑且認爲這種情況下被默認提升爲2字節。
擴展爲兩字節,有符號數是按符號位擴展的, c被擴展成 1111 1111 1000 0000
uc擴展成 0000 0000 1000 0000
相加結果 0000 0000 0000 0000(最高位被捨棄,即使提升爲四字節 同樣最高位捨棄)
所以 us= 0 第一個輸出 0x0
us= (unsigned char)c + uc
c被強制類型轉化成unsigned char c中的存儲內容並沒有變 1000 0000 只是類型變化,也就是解釋這段內存的方式變化, 這段內存中的數據被看做unsigned char
所以 相加前 擴展
c擴展成 0000 0000 1000 0000
uc 0000 0000 1000 0000
結果 0000 0001 0000 0000
us = 0000 0001 0000 0000 (128 + 128 = 256)
第二個輸出爲 0x100
us = c +(char)uc
同理 c擴展 1111 1111 1000 0000
uc擴展 1111 1111 1000 0000
結果 1111 1111 0000 0000(最高進位捨棄)
us = 1111 1111 0000 0000(這是 -256 的補碼,從數學角度看 -128 +(-128)= -256 但us 是unsigned short 這段內存並不被解釋爲 -256)
第三個輸出爲 0xff00
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
第一次做這道題搞得很混亂,既想從編碼存儲角度去考慮又想從數學十進制加法的角度考慮,結果因爲對編碼 存儲等知識不太瞭解,不知道相加時的類型提升,推出的結果總是自相矛盾。。。。。
從這道題想到了整數的編碼,計算機中爲什麼要用補碼存儲整形數據? 補碼爲什麼是原碼取反加一這種形式???
計算機採用補碼,應該是遵循 “簡單”的設計想法,把複雜的問題簡單化。 如果能夠把加法和減法統一用加法器來處理,那在硬件啊電路啊 設計方面 可能省去很大麻煩。(我是這麼猜的)
然後問題是 如何用加法實現減法? 沉思之際,擡頭一撇,發現一隻野生鐘錶 。。。
從6點想把指針撥到4點 可以逆時針撥2格,也可以順時針 撥 10 格
6 - 2 = 4
6 + 10 = 4
減 2 等價於加上(12 -2) 12 是鐘錶的模
這樣就用加法實現了減法減去一個n位 二進制數x 等價於 加上 (2的n次方(模)- x)
(2的n次方 - x) 就是x取反加一,即x的補碼 所以用這種形式的補碼實現了減法變加法