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

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

編輯:關於C語言

  C語言學習筆記        

          之     深入解剖unsigned int 和 int

就如同int a;一樣,int 也能被其它的修飾符修飾。除void類型外,基本數據類型之前都可以加各種類型修飾符,類型修飾符有如下四種:

1.signed----有符號,可修飾char、int。Int是默認有符號的。

     2.unsigned-----無符號,修飾int 、char

     3.long------長型,修飾int 、double

     4.short------短型,修飾int

我們主要來看一下signed和unsigned與int之間的聯系與區別。

    什麼叫做有符號,什麼叫做無符號

  這個問題其實很簡單,比如:5和-5,5沒有符號,-5有符號。簡單吧。但是在計算機中的這種符號可不簡單。我們分別來看一下:

在說明有符號和無符號的區別之前,我們必須先知道溢出是怎麼回事,因為有無符號的根本原因可以說就是因為數據出現了溢出現象導致的。

溢出:

我們知道數據在計算機中以二進制存儲,並且占據一定的空間,而這個空間屬於計算機分配的空間。

計算機給int分配32位或者16位不同電腦可能不同)的空間,既然空間有限,那麼數值就會有限制,就會存在最大值與最小值這一說,比如:假設int類型的分配16位,無符號類型的最大值為1111 1111 1111 111116個1),也就是65535,如果超過了65535,這就叫做溢出,那該怎麼辦? 如果要輸出65536,那將會輸出個什麼東西呢? 下面和大家一起看一下:

疑問:有的讀者會問:65535這麼小啊,我記得自己在輸出比65535大好多的數也能夠輸出啊。

  解答: 那就是有無符號的定義和你電腦編譯器的原因了。64位的電腦和32的電腦可是不一樣的哦。而且int占幾個字節是與電腦編譯器有關的。不過現在大部分電腦int占4個字節,即32位,那麼他的最大值可是32個1(二進制)左右的數量級,你實驗過這麼大的數嗎?

1.無符號整型(unsigned  int)

1)我們都知道整型是4個字節有些編譯器不同,可能會是2個),即32位,無符號整型當然也為32位。

2)既然是32位,無符號整型的取值是32個0~32個1,即:0~4294967295

3) 我們舉個例子:32位有點長,所以我們拿16位的unsigned short int 來舉例。

short int 是16位的,無符號的范圍是0~65535

  就拿十進制的32767以下的所有舉例均拿這個數字來說事了)來說,它的二進制為:

               0111 1111 1111 1111

  對於無符號的整型32767來說,它的二進制的最高位稱為數據位,即那個0就是數據位,數據位是要參與運算的,如果我們把0改成1,即16個1,它的十進制就是65535就是2的15次方+2的14次方...一直加到2的0次方),這是不同於有符號整型的。

4) 為了進行理解3)中的含義,做一個程序說明:


#include <stdio.h>
main()
{
    unsigned short int a=32767,b=a+1;//定義短整型無符號
    printf("a=%u\nb=%u\n",a,b);//以無符號輸出
}


定義的時候a=32767,也就是0111 1111 1111 1111,輸出的依然是32767,

a+1=32768, 二進制為1000 0000 0000 0000,輸入依然為32768

根據3)中講解的,無符號整型的二進制最高位為數據位,數據位為0為1都是按照正常來算的。

2.有符號整型signed)int)

(1)int類型默認是有符號的,所以int實際上是signed int ,我們通常省略signed

(2)有符號整型也是32位。

3)它的取值范圍就與無符號整型不同了。它的范圍是-2147483648~2147483647這個范圍可以理解為無符號整型的一半變成了負數。

    32位有點長,所以我們拿16位的short int 來舉例。

short int 是16位的,有符號的范圍是-32768~32767


這個時候可能就有人發問了,32768用二進制表示為1000 0000 0000 0000,那麼這個負的32768的負號又怎麼理解呢?看下面

4)舉個例子;

還是以32767為例子,它的二進制為:

      0111 1111 1111 1111

對於有符號整型32767來說,它的二進制最高位稱為符號位而不是數據位了),符號位顧名思義就是決定正負號的,規則:0是正,1為負

(5)列舉一個程序理解4)的內容


#include <stdio.h>
main()
{
   short int a=32767,b,c,d;//定義無符號類型。
b=a+1;
c=a+2;
d=a+3;
   printf("a=%d\nb=%d\nc=%d\nd=%d\n",a,b,c,d);
}


可以看出此時的結果竟然是這個樣子的。為什麼呢?怎麼回事?

  其實在計算機中,負數是並不存在的,它是以二進制補碼的形式表示和存放。什麼是補碼呢?

6)什麼是補碼,補碼的運算。

我們還是列舉一個簡單的例子吧!就用-6.

我們經過以上的學習已經知道負數的符號位為1,所以:

 1)-6的二進制: 1000 0000 0000 0110稱為原碼,原碼是計算機顯示給我的)

 2)對原碼求反碼:1111 1111 1111 1001稱為反碼,保持符號位不變,將原碼中的0變1,1變0)

 3)對反碼加1:1111 1111 1111 1010稱為補碼,補碼是計算機中存儲負數的形式)

在計算機中,如果存儲的二進制是1111 1111 1111 1010,那麼顯示在我們前台的十進制數字就是-6。即:負數在計算機中是以該負數的二進制的補碼形式存儲的。

7)了解了什麼是補碼後,再來看我們上述說的那個程序:

  32767的二進制為:0111 1111 1111 1111

我們來計算一下c的值為什麼會等於-32767

c=32767+2,c的二進制為:1000 0000 0000 0001(32767的二進制+2),c的這個二進制是在計算機中存儲的補碼,需要將它轉換為原碼,也就是將c的二進制數減一再取反。得到的二進制原碼為:1111 1111 1111 1111。我們已經說過,符號位為1,表示負值,並不參加運算,所以此二進制的十進制為:-32767。

但是,上述中,c的原碼的確是1111 1111 1111 1111,c在計算機中存儲的補碼也的確是1000 0000 0000 00010。但是-32767的由來卻有另一種理解,c的補碼是16位,32位編譯器中有32位的二進制,也就是說在16位補碼的前面還有32-16=16)位的虛位數,並不屬於計算機給short int分配的空間,但是這16位的位數當數表示正時為0,當數表示負數時為1。並且前16位的數字全部都與二進制倒數第8位的數字一致。也就是說:

  c 的補碼是   1...1 1000 0000 0000 0010(1..1表示16個1)

我們可以這樣計算:-2的7次方+2的1次方=-32767,這種理解普遍被大眾所接受,而且避免了原碼的概念。


8)通過程序也可以發現一個規律,int的取值范圍是-32768~32767,把頭尾連接起來形成一個環就可以了。


通過上述一系列的講解,大家是不是有點暈了,當然對於有基礎的讀者,可能越看越明白,對於本來就接觸不多的讀者,肯定暈了,因為我也快暈了,呵呵!

你可能會有這樣的疑惑:程序運行後的答案總不是自己所想的那樣,沒錯,因為數據類型的范圍限制,如果超出了,就說明溢出了。

如果還是不明白的話,我們再接著看下一篇:C語言進階暑期特別篇)深入剖析un)signed及溢出中)

   在下一篇中,我和大家一起學習unsigned char和signed char的,char和int其實是一樣的,本來沒什麼可說的了,但是我和廣大犯暈的讀者一樣,都想多找幾個這樣的解析和例子來看看,那就用下一篇文章來加強一下關於有無符號的學習吧!

本文出自 “趙玉強的博客” 博客,謝絕轉載!

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