程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C語言進階【暑期特別篇】深入解剖(un)signed及溢出(中)

C語言進階【暑期特別篇】深入解剖(un)signed及溢出(中)

編輯:關於C語言

C語言學習筆記

之 深入剖析un)signed char 及溢出

一:signed char 和unsigned char 的取值范圍

Char和int 一樣,都有有符號和無符號之說。即unsigned char和signed char。

1.C語言中我們用的char默認到底是有符號還是無符號的呢?

對於不同的教材會有不同的答案,其實有無符號都是自己電腦的編譯器決定的。注意:我的電腦默認是有符號的,以下實例都是按我的電腦默認的程序)

2. 有)無符號 char類型的取值范圍。

我們知道char類型所占據的空間內存一般是1個字節8位),signed char和unsigned char當然也是占1個字節8個位數。但是和int類型一樣,它們的取值范圍是有區別的。

Unsigned char類型的取值范圍是:0~255

Signed char類型的取值范圍是:-128~127

二:signed char 和 unsigned char 的溢出問題

其值在范圍內時,會被正常處理,但是超過范圍就會發生我們所說的溢出。但是要注意的是,在范圍之內也並不意味著它就是可打印的字符。

1. 來看一下unsigned char類型的溢出問題

關於上界溢出

十進制

二進制

254

1111 1110

254

255

1111 1111

255

256

257

關於下界溢出

十進制

二進制

2

0000 0010

2

1

0000 0001

1

0

0000 0000

0

-1

-2

我們已經說過了unsigned char 的取值范圍是0~255,通過上述兩個表格:

在上界中254,255都能正常表示,那256和257它們不在計算機分配的范圍之內,它們是溢出了,那問號處的值應該怎麼表示呢?

同樣的,在下界中,0,1和2都在范圍之內,能正常表示,-1和-2很明顯溢出越界了,那怎麼表示呢?

2.再來看一下signed char類型的溢出問題

關於上界溢出

十進制

二進制

126

0111 1110

126

127

0111 1111

127

128

129

關於下界溢出

十進制

二進制補碼形式)

-127

1000 0001

-127

-128

1000 0000

-128

-129

-130

我們也已經知道了signed char的取值范圍是:-128~127.

在上界中,126和127在范圍之內,都能正常顯示值。但是128和129呢?

在下界中,-127和-128在范圍之內,都能正常顯示值。但是-129和-130呢?

三:signed char 溢出的表示

1.程序實例驗證一下signed char中溢出的數字的值求signed char溢出中的問題)


#include <stdio.h>
main()
{
    signed char a=126,b=127,c=128,d=129;
    printf("a=%d\nb=%d\nc=%d\nd=%d\n",a,b,c,d);
}


174922885.png


#include <stdio.h>
main()
{
    signed char a=-127,b=-128,c=-129,d=-130;
    printf("a=%d\nb=%d\nc=%d\nd=%d\n",a,b,c,d);
}


174940112.png

從上述兩個程序中,我們不難得出以下結論的表格數據。

2.給出signed char溢出問題表格的答案:

關於上界溢出

十進制

二進制

126

0..0 0111 1110

126

127

0..0 0111 1111

127

128

1..1 1000 0000

-128

129

1..1 1000 0001

-127

關於下界溢出

十進制

二進制補碼形式)

-127

1..1 1000 0001

-127

-128

1..1 1000 0000

-128

-129

0..0 0111 1111

127

-130

0..0 0111 1110

126

注:0..0 表示24個0,1..1表示24個1

3.解析

從上述兩個表格中可以看到,不管是否超過上下屆,不管是負數還是正數,每增加減少)一個單位,就直接在二進制表示的最後一位上加減)1個單位。

並且相加和相減時,都先不看前24位,如果倒數第8位變為1,則前面24位全部設置為1,該數被解釋為負數;如果倒數第8位變為0,則前面24位全部設置為0,該數被解釋為正數。

我們來分別看看。

1)126和127

126和127是范圍之內的數字,他們的值是遵從規則的。所以他們的值也是126和127,並沒有越界。

2)128

從程序實驗和上表的結論中,我們得出了128的值竟然是-128.128這個數字是越界的數字,是127+1。

這時會在127的最後8位上加1,也就是在0..0 0111 1111的後8位0111 1111上加1,變為1000 0000。倒數第8位變成了1,所以前24個位也全部變為1,所以該數被表示為負數。它的值為 -1*2^7+0=-128。

根據負數的值在計算機中是以補碼的形式存儲的理論,也就是說1000 0000是補碼,即:-128在計算機中是以1000 0000存儲的,-128的原碼是1000 0000補碼)減1,再取反,結果還是1000 0000原碼)。

3)129

129和128的取值也是一樣的道理。129是127+2或者128+1,拋開前24位不說,它的二進制為1000 0001,倒數第8位為1,所以前24位也為1,並且為負數。所以它的值表示為: -1*2^7+1=-127.

根據負數的值在計算機中是以補碼的形式存儲的理論,1000 0001是補碼,即:-127在計算機中是以1000 0001存儲的,-127的原碼是1000 0001補碼)減1,再取反,結果是0111 1111原碼)。

4)-127和-128

這兩個數字都是在范圍之內 沒有什麼可說的了吧,並且它們的二進制形式也剛剛講過了。

5)-129

-129是-128-1所得,所以-128的最後8位是1000 0000,減去1變為0111 1111,前面24位全部置位0,且該數被解釋為正數,其值為2^0+2^1+2^2+2^3+2^4+2^5+2^6=2^7-1=127

6)-130

-127的最後8位是1000 0001,減去3變為0111 1110,前面24位全部保持0,且該數被解釋為正數,其值為2^1+2^2+2^3+2^4+2^5+2^61=126

四:unsigned char 溢出的表示

看了上述的講解 ,我相信讀者一定對unsigned char也明白了,無符號無非就是取值范圍不一樣而已。不過我們還是來一起看一下。總覺得不放心 呵呵

1.程序實例驗證一下unsigned char中溢出的數字的值求unsigned char溢出中的問題)


#include <stdio.h>
main()
{
    unsigned char a=254,b=255,c=256,d=257;
    printf("a=%u\nb=%u\nc=%u\nd=%u\n",a,b,c,d);
}


174958991.png


#include <stdio.h>
main()
{
    unsigned char a=1,b=0,c=-1,d=-2;
    printf("a=%u\nb=%u\nc=%u\nd=%u\n",a,b,c,d);
}


175014280.png

從上述兩個程序中,我們不難得出以下結論的表格數據。

2.給出unsigned char溢出問題表格的答案:

關於上界溢出

十進制

二進制

254

0..0 1111 1110

254

255

0..0 1111 1111

255

256

0..0 0000 0001

0

257

0..0 0000 0001

1

關於下界溢出

十進制

二進制

2

0..0 0000 0010

2

1

0..0 0000 0001

1

0

0..0 0000 0000

0

-1

0..0 1111 1111

255

-2

0..0 1111 1110

254

注:0..0 表示24個0,1..1表示24個1

3.解析

其實和有符號基本相同,唯一的差別就是,前面的24位一直都是0,並且該數永遠都是正數。我們說幾個吧。

比如256,256=255+1所得,255為0..0 1111 1111,然後加1,雖然255的全碼都是1,再加1貌似沒法加了,但是我們仍可將1111 1111前面一位加1,最後得到0001 0000 0000,之後我們就只看後8位即可,所以256的值是0.

比如-1,-1=0-1所得,0000 0000減1相當於減去0000 0001,雖然0的全碼是0…0 0000 0000,似乎往上也沒法借位,但是我們仍可將0000 0000前面一位加上1,看做0001 0000 0000減去0000 0000 0001,最後得到0000 1111 1111,我們直接取最後8為即可。

五:疑惑

對於無符號型,前24位永遠為0,對於有符號型,前24位永遠和倒數第8位一樣。這個定律可要記清楚了

不知道和大家學習了有無符號char類型以及幾個例子,有沒有對unsigned 和signed了解了很多呢。在上一篇C語言進階暑期特別篇】深入解剖un)signed及溢出上)中的unsigned int和signed int其實和我們這一篇講的是一個道理。

看完C語言進階暑期特別篇】深入解剖un)signed及溢出上)和C語言進階暑期特別篇】深入解剖un)signed及溢出中)兩篇文章後,我和讀者都有一個問題和疑惑,在程序中定義什麼類型就以什麼類型輸出的,如果不是呢?比如:變量a定義為unsigned無符號),但是我們在輸出的時候以signed(有符號)%d)輸出,那又會如何呢?相同的,定義為signed,但是以unsigned輸出,結果又會是如何呢?

這個問題就在下一篇文章C語言進階暑期特別篇】深入解剖un)signed及溢出下)中學習吧。下一篇中我們主要是以一個實際的程序例子來展開陳述,來總結有無符號。


本文出自 “趙玉強的博客” 博客,請務必保留此出處http://zhaoyuqiang.blog.51cto.com/6328846/1259300

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved