天天看點

C++ 原碼、補碼和反碼解析

首先對于有符号數,第一位的位置是表示的正負,為1時是負數,為0時是正數

其次,正數的原碼、補碼、反碼一緻

負數的反碼是原碼的數值位(也就是除了第一位的符号位之外)取反,負數的補碼是反碼加1 

在計算機中帶符号的整數都是采用二進制的補碼進行存儲,資料在記憶體中始終是以二進制形式存放的,數值是以補碼表示的。

無論32位還是64位,int都是4個位元組,32位,表示的範圍為-2147483648~2147483647,32為最小負整數的補碼表示為:1000 0000 0000 0000 0000 0000 0000 0000

~i 對每一位取反運算

-i 取反加1

1-i 補碼+1的補碼

-1-i -1的補碼加上-i的補碼

計算機中的有符号數和無符号數的機器碼(補碼)是一樣的,同一個二進制碼按照有無符号輸出結果不一樣。

//關于資料在計算機記憶體中的存儲:無論什麼數值,也無論這個數值是用什麼進制表示,計算機存儲的都是這個數值的補碼。

//如果表示這個數值的時候,前面有+号或者沒有加符号,則認為是正數,這個時候就是把這個數值轉換為二進制後直接存入計算機,因為正數的補碼就是其本身(注意:存儲的時候隻會看有沒有加+号來辨別,而不看其實際意義,如(int)x80000001前面沒有加符号,則預設其是一個正數,盡管它最高位是并且如果看成正數則實際上已經越界,在存入計算機的時候也會當做正數來計算補碼然後存入計算機,這一點可以通過檢視memory來證明,記憶體中也是存儲的x80000001);

//如果表示這個數值的時候,前面加了-号來辨別這是一個負數,則需要先轉換成二進制再按照計算負數補碼的步驟變換成補碼再存入計算機記憶體,(注意:存儲的時候隻會看有沒有加-号來辨別,也不看起實際意義,如(int)-0x80000001是一個負數,盡管這個數值已經沒有實際意義,因為如果将後面看做一個正數實際上已經越界,整體上如果看成負數也已經越界,但是計算機會計算它的補碼,然後存入記憶體這一點可以通過檢視memory來證明,記憶體中存儲的是x7fffffff

//關于補碼的計算規則:以前一直是将原碼除符号位逐位取反,然後末位加得到補碼,但是這樣-0x80000001得到的補碼應該是xffffffff,但是實際檢視得到的是x7fffffff。是以應該是,将-号後面的數隻管展開成正數的二進制形式,如果不夠所需的類型的長度前面補零,如果超過了将超出的位數舍棄,然後除了所需類型的最高符号位之後的都逐位取反末位加,最後将符号位加,溢出的位舍去,這樣-0x80000001的補碼計算之後得到的就是x7fffffff。這個補碼的計算方法可以通過計算short類型的-0x18001來得到确認(開始的時候推測是将-0x80000001擴充成了long之後求補碼截斷所得,但是通過求sizeof(0x80000001)得到的是否定了這種假設)。

//關于數值類型擴充:當需要把一個短類型轉換成一個長類型的時候,需要先将數值轉為補碼形式,然後通過位擴充來進行,在位擴充的時候,隻看需要擴充的數值的符号位,如果是則将符号位之前填充即可,如果是1則填充1需要将一個長類型轉換成一個短類型的時候,先将這個數值表示為補碼形式,然後從後向前截取需要的位數即可。。

繼續閱讀