數據在計算機中的存儲之--正負整數


 

 段落1. 百度百科char

char用於C或C++中定義字符型變量,只占一個字節,取值范圍為 -128 ~ +127(-2^7~2^7-1

 

知識點:負數在計算機中以補碼存儲,而正數以原碼存儲。

為什么負數在計算機中以補碼存儲呢?

因為所以科學道理,可以看這篇知乎文章:https://www.zhihu.com/question/335614901/answer/755608419 

不看也可以,只要知道負數在計算機中有用補碼來存儲的必要性就行了,而且這個必要性是有科學道理的。

 

 

段落2.   求正數在計算機中存儲的二進制值

請問 char j = 5 這句代碼中,  j 在計算機中存的二進制值是多少?

正數以原碼存儲,5的原碼是0b0000 0101.   所以 j 在計算機中存的二進制值是 0b0000 0101 。

 

 

段落3.   求負數在計算機中存儲的二進制值

請問 char j = -12這句代碼中,  j 在計算機中存的二進制值是多少?

負數以補碼存儲

先找對該負數對應的正數,即12。 12 的原碼是 0b0000 1100 .    

我們將上述原碼的最高位置為1, 得到0b1000 1100.

然后再求補碼:

0b1000 1100 , 符號位不變,其余各位取反 =》0b11110011 再加1 =》得到0b11110100 。

我們最終理論計算得到0b11110100, 這等價於0xF4。

 

但是寫代碼驗證的時候還是有所區別,在%s、%c、%d、%x等這些輸出格式選項中,我們只能使用%x來打印出其十六進制的內存值。

而且%x會打印出4字節,並非只有1字節哦,所以,我們只需關注最低一個字節就行了。

下面是代碼:

#include <stdio.h> #include <string.h> #include <assert.h> #include <stdlib.h> #include <unistd.h>

int main(){ char j = -12; printf("%x \n", j); return 0; }
root@lmw-virtual-machine:/home/lmw/桌面/C_Text# ./ab
fffffff4 
root@lmw-virtual-machine:/home/lmw/桌面/C_Text# 

  可以看到,最低字節是F4。

 

 上面提到可以先找到該負數對應的正數12, 那么12的原碼可不僅僅是0b0000 1100 , 還可以是0b 0000 0000 0000 0000 0000 0000 0000 1100 (32位, 合計4字節

 相同的操作手法我們再來一遍,

 我們將上述原碼的最高位置為1, 得到0b1000 0000 0000 0000 0000 0000 0000 1100 .

 然后再求補碼:

 符號位不變,其余各位取反 =》0b1111 1111 1111 1111 1111 1111 1111 0011,  再加1 =》得到 1111 1111 1111 1111 1111 1111 1111 0100 

 我們最終得到的0b1111 1111 1111 1111 1111 1111 1111 0100 則等價於 0xFFFFFF4。

 

 0b1111 1111 1111 1111 1111 1111 1111 0100  和 0b11110100 都可以表示 -12 的計算機存儲值啊 , 那什么時候是前者,什么時候是后者呢?

 取決於我們希望用什么方式去訪問這片內存。 

 如果是使用%x訪問, %x一定會訪問到4字節內容並以十六進制顯示, 那么得到的就是4字節的0xFFFFFFF4,

 對應的是4字節的0b1111 1111 1111 1111 1111 1111 1111 0100,

 即使用%x訪問時,12的原碼應該按照4字節來分析。 

  

段落4.  超限處理

如果賦值的數是超過char類型的上限值的,那么先減去256的倍數, 再根據上面方法計算其在計算機中存儲的二進制值。

 

例如上圖,我們要計算500賦值給char,那么只需要計算500-256=244, 發現244還是大於char的取值上限,

那么再次244-256 = -12, 發現-12 在char類型范圍內,所以我們只需要計算-12在計算機中的存儲值即可,

這樣我們也能夠可以分析出使用%x打印變量a會得到怎樣的十六進制值了。

換句話說,這基於一個觀點: char a = 500; 等價於 char a = -12; 

 

段落5.   不同符號類型數做加法時  

 知識點:當有符號數與無符號數一起運算時,會將有符號數轉換為無符號數!

下面的demo可以作為面試題使用。如果面試者只能解釋到34-12=22這種地步,那么顯然是非常錯誤的。

#include <stdio.h> #include <string.h> #include <assert.h> #include <stdlib.h> #include <unistd.h>

int main(){ char j = -12; // 0xFFFFFFF4 unsigned char x = 34;  // 0xFFFFFFF4 + 0x22(十進制的34) ,得到0x1 0000 0016
 printf("%x \n", j+x); // 0x1 0000 0016 超過了4字節了,截斷得到 0x00000016, 即0x16 
 unsigned int sum = j+x; printf("sum = %d \n", sum); // 0x16,即 22

    return 0; }

 

 

 

補充點:

  補充一個%x 和 %lx的實驗

#include <stdio.h> #include <string.h> #include <assert.h> #include <stdlib.h> #include <unistd.h>

int main(){ printf("%d, %d, %d \n", sizeof(char),sizeof(int),sizeof(unsigned long int)); char j = -12; printf("%x \n", j); printf("%lx \n", j); int j_int = -12; printf("%x \n", j_int); printf("%lx \n", j_int); unsigned long int j_long_int = -12; printf("%lx \n", j_long_int); printf("%x \n", j_long_int); return 0; }
root@lmw-virtual-machine:/home/lmw/桌面/C_Text# ./ab 1, 4, 8 fffffff4 fffffff4 fffffff4 fffffff4 fffffffffffffff4 fffffff4 root@lmw-virtual-machine:/home/lmw/桌面/C_Text#

結論:

%lx的特點:如果被打印的數據不足8字節,例如只有4字節或1字節,那么就只會打印4字節。如果被打印的數據有8字節,那么就會打印出8字節。

而%x一定會打印出恰好剛好4字節。

 

.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM