【C語言深度剖析】讀書筆記之 signed ,unsigned

pengfoo發表於2012-09-02

1.4,signed、unsigned 關鍵字
我們知道計算機底層只認識0、1.任何資料到了底層都會變計算轉換成0、1.那負數怎麼儲存呢?肯定這個“-”號是無法存入記憶體的,怎麼辦?很好辦,做個標記。把基本資料類
型的最高位騰出來,用來存符號,同時約定如下:最高位如果是1,表明這個數是負數,其值為除最高位以外的剩餘位的值添上這個“-”號;如果最高位是0,表明這個數是正數,
其值為除最高位以外的剩餘位的值。這樣的話,一個32位的signed int型別整數其值表示法範圍為:- 2^31~2^31 -1;8 位的char型別數其值表示的範圍為- 2^7~2^7 -1。一個32位的unsigned int型別整數其值表示法範圍為:0~ 2^32 -1;8位的char型別數其值表示的範圍為0~2^8 -1。同樣我們的signed 關鍵字也很寬恆大量,你也可以完全當它不存在,編譯器預設預設情況下資料為signed 型別的。
上面的解釋很容易理解,下面就考慮一下這個問題:
int main()
{
char a[1000];
int i;
for(i=0; i<1000; i++)
{
a[i] = -1-i;
}
printf("%d",strlen(a));
return 0;

下面的補碼錶示數:
11111111	-1
11111110	-2
11111101	-3
11111100	-4

……		……

10000001	-127
10000000	-128
01111111	-129

……		……

00000000	-256

此題看上去真的很簡單,但是卻鮮有人答對。答案是255。別驚訝,我們先分析分析。
for 迴圈內,當i 的值為0 時,a[0]的值為-1。關鍵就是-1 在記憶體裡面如何儲存。
我們知道在計算機系統中,數值一律用補碼來表示(儲存)。主要原因是使用補碼,可
以將符號位和其它位統一處理;同時,減法也可按加法來處理。另外,兩個用補碼錶示的數
相加時,如果最高位(符號位)有進位,則進位被捨棄。正數的補碼與其原碼一致;負數的
補碼:符號位為1,其餘位為該數絕對值的原碼按位取反,然後整個數加1。
按照負數補碼的規則,可以知道-1 的補碼為0xff,-2 的補碼為0xfe……當i 的值為127
時,a[127]的值為-128,而-128 是char 型別資料能表示的最小的負數。當i 繼續增加,a[128]
的值肯定不能是-129。因為這時候發生了溢位,-129 需要9 位才能儲存下來,而char 型別
資料只有8 位,所以最高位被丟棄。剩下的8 位是原來9 位補碼的低8 位的值,即0x7f。
當i 繼續增加到255 的時候,-256 的補碼的低8 位為0。然後當i 增加到256 時,-257 的補
碼的低8 位全為1,即低八位的補碼為0xff,如此又開始一輪新的迴圈……
按照上面的分析,a[0]到a[254]裡面的值都不為0,而a[255]的值為0。strlen 函式是計
算字串長度的,並不包含字串最後的‘\0’。而判斷一個字串是否結束的標誌就是看
是否遇到‘\0’。如果遇到‘\0’,則認為本字串結束。
分析到這裡,strlen(a)的值為255 應該完全能理解了。這個問題的關鍵就是要明白char
型別預設情況下是有符號的,其表示的值的範圍為[-128,127],超出這個範圍的值會產生溢
出。另外還要清楚的就是負數的補碼怎麼表示。弄明白了這兩點,這個問題其實就很簡單了。

相關文章