轉載自大佬的博客https://blog.csdn.net/youyou362/article/details/72667951/
1·先說明負數怎么儲存
(1)十進制負數是以其補碼儲存在內存上。
驗證:求-8在內存上以二進制形式1的個數
思路是:拿變量,令值為1,與-8的二進制碼的每一位做與運算,若與運算結果為1,則該位為1。
代碼:
int NumberOf1(int n) { int count = 0; unsigned int value = 1; while (value != 0) { if (value&n) { count++; } value = value << 1; //左移右邊補0,當移完32為value為0. } return count; }
結論:
輸入-8,結果為29。
在32位系統上,-8的儲存
-8的儲存是以-8的補碼,儲存在內存上。
-8的原碼 1000 0000 0000 0000 0000 0000 0000 1000
取反 由於第一位是符號位 不用改變 得:1111 1111 1111 1111 1111 1111 1111 0111
補碼=反碼+1 得::1111 1111 1111 1111 1111 1111 1111 1000
得到1的數量正好為29,所以-8的補碼就是-8儲存在內存上的二進制碼
(2)但是在十六進制,負數在內存中儲存的是原碼
驗證:
對int test = 0x80000001 (對應十進制為-1) 檢查其內存上的1的個數,發現只有2個1
故內存上原碼為 1000 0000 0000 0000 0000 0000 0000 0001.
對十六進制的-8也是2個1
(3)我們來看看0x80000000的輸出
0x80000000 的二進制位
原碼 1000 0000 0000 0000 0000 0000 0000 0000
若最高位為符號位,則為-0,可是輸出int i = 0x80000000 發現i= -(2^31)
原因是在十六進制中負數的二進制原碼的最高位是符號位,后面的31位為序號位,不是值位。1后面的000 0000 0000 0000 0000 0000 0000 0000,表示序號1,表示負數中,從小到大的第一位。
由於int的最小值為-2^31,排在負數從小到大的序號1,所以int i = 0x80000000 輸出為 -(2^31)
我們來看看0xFFFFFFFF
原碼 1111 1111 1111 1111 1111 1111 1111 1111
最高位為1 ,為負數,序號位為第(2^31)-1位 (111 1111 1111 1111 1111 1111 1111 1111=(2^31-1) 所以0xFFFFFFFF為負數從小到大 第2^31-1位 ,即
-2^31+2^31-1= -1
輸出int i = 0xFFFFFFFF 為 -1 符合
(4)十進制的補碼也符合 符號位+序號位的原則
就拿-8來做例子:
-8的補碼:1111 1111 1111 1111 1111 1111 1111 1000 可以看出最高位為1 序號位為第2^(31)-8位,(111 1111 1111 1111 1111 1111 1111 1000 = 2^(31)-8 )
則該補碼表示的值為2^31- 2^(31)-8 = -8 符合
------------------------------------------------------------------------
相關知識點補充:
十六進制用最高位作為符號位,1位負數,0為正數。
負數的位右移運算:
原則:若右移的數字為負值,則向右移動N位同時N個1補充在左邊
若為正值,則以N個0補充在左邊
---------------------