前言:過年偷懶了(●ˇ?ˇ●),但是年后開學了一定要恢復學習狀態,在復習加繼續學習的途中,我發現對于unsigned關鍵字的掌握并不是很熟練,于是翻閱了各個大佬的博客以及書籍,總結了對于unsigned的一些知識點。(如有不對的地方,歡迎各位大佬指正🤭)
什么是unsigned?
從字面上來看,不難理解,unsigned是無符號的意思,事實上,的確沒錯。它在C語言中和signed相反,signed是有符號的意思。其實C語言中的類型基本上都是有符號類型,只是省去了signed,
比如:(signed)int --> int
(signed char)-->char (這個取決于編譯器,絕大多數編譯器都是這個,比如我們常用的VS)
在了解什么是無符號之前,我們先了解一下什么是符號位:(知道的童鞋可以跳過了)
在計算機處理二進制數據時,專門規定了一位符號位,來確定數據的正負,這個符號位通常是數據的最高位,如8比特位數據,左邊第一位就是符號位,剩下七位用來表示數據大小。
看例圖:

在知道符號位之后就很容易理解無符號了,無符號嘛就是沒有符號位,原來的符號位可以列入計算了。值得一提的是,無符號數都是非負數。

unsigned的深入理解
對于有符號類型的整形打印的時候用%d,對于無符號類型的整形打印時用%u
來看一下下面這幾個典型例題,讓你捋清它們之間的關系并且對unsigned有進一步的了解
例一:


我們將a初始化為無符號整形,將他以%u的形式打印時,我們知道整數在計算機中存儲是以二進制序列補碼的形式存儲的,正數的補碼和原碼一樣,但是負數的補碼是通過原碼到反碼到補碼轉換得到的。(這個會放在最后說)
-1的補碼是11111111111111111111111111111111(共計32位,因為int類型是4個字節,即32個比特位)
按照等比數列求和公式計算得到2^32-1=4294967295. 這與代碼跑出來的結果一致。
但是以%d的形式打印時為什么是-1呢?因為以%d形式打印時,系統會將a認為是有符號整形,自然而然的將第一位視為了符號位,經過反碼到原碼的反變換得到原碼是:10000000000000000000000000000001 即 -1。

我們經過調試發現在僅以%d形式打印完后,a的數值仍是4294967295。這說明在printf函數內部進行打印時以怎么樣的類型打印并不改變數據原來的類型。
例二:


對于這個題中涉及到了整型提升,如果不理解整型提升是無法理解這道題的。
所以在解決這道題之前,先簡單解釋一下什么是整型提升
整型提升:
整型提升是C程序設計語言中的一項規定:在表達式計算時,各種整型首先要提升為int類型,如果int類型不足以表示則要提升為unsigned int類型;然后執行表達式的運算。
這是百度百科里面給的解釋,是不是有些難以理解?那么來點通俗易懂的。
對于這道題來講,就是以%d(4字節)打印的時候,不足四個字節的類型比如short,char等類型就要發生整型提升來補到4個字節,正數補0,負數補1(往左端補)。比如變量a,它的類型是char類型,大小是1個字節,它的補碼是11111111,8個比特位,因為要以%d形式打印,所以要發生整型提升,就變成了11111111111111111111111111111111
打印時仍然為-1。
同樣變量b的類型是short,大小為兩個字節所以發生整型提升后也為11111111111111111111111111111111,結果為-1
變量c和變量d都是不足4字節的無符號整形,(無符號整形視為非負數)發生整型提升時前面補0,最終序列為
c:00000000000000000000000011111111 ---->2^8-1=255
d:00000000000000001111111111111111 ----->2^16-1=65535
而變量e本身就是4個字節,無需發生整型提升。因為是無符號整型,所以視為非負數,原碼反碼補碼都一樣,2進制補碼為11111111111111111111111111111111
以%d形式(有符號整形)打印時第一位視為符號位,則視為負數,通過轉換得到原碼
10000000000000000000000000000001--->-1,最終結果為-1
由此我們得到結論:
對于負數:
//1.不發生整型提升的情況下,有符號數和無符號數以%u打印結果一樣。(因為以無符號整型打印,都吧把符號位納入計算)
//2.發生整型提升的情況下,有符號數前面補1,無符號數補0
例三:


通過之前的學習我們知道,sizeof是用來計算大小的單目操作符,那么a的類型是int,sizeof(a)是4,那顯然-1<4啊,理應輸出<,但是系統卻輸出了>,這是為什么呢?

通過查詢MSDN我們發現sizeof返回值是size_t類型,也就是unsigned int類型。
那么在a和其做比較時,a會被轉換為無符號類型作比較。a被轉換為無符號類型后大小為2^32-1,顯然大于4,所以輸出 >
By the way:此處的a仍然為int類型,只是作比較時視為無符號類型喲,和之前的printf有異曲同工之處。
結論:在將一個有符號整形和無符號整形作比較時,會將有符號整形視為無符號整形來作比較,但不改變有符號整形變量的性質。
附:計算機中二進制數據的原碼反碼補碼。
整形數據在計算機中存儲時都是以補碼形式存儲的,因為:
補碼使得符號位能與有效值部分一起參加運算,從而簡化運算規則。
使減法運算轉換為加法運算,進一步簡化計算機中運算器的線路設計。
保證了0的唯一性,保證了數的表示的準確性。
對于正數來講:
原碼反碼補碼都相同
對于負數來說:
反碼=原碼符號位不變,其他位按位取反
補碼=反碼+1
舉個例子:-10(以8bit位數據為例)
原碼:10001010
反碼:11110101
補碼:11110110
結語:
對于整數其實不管怎么存,它的二進制序列是不變的,只是解釋的方式不同,那么打印出來的數值就不同了.
ok辣,以上就是unsigned的詳細講解了。如有錯誤,歡迎指正qaq;如有不足,歡迎補充!
繼續加油啊,還是那句話:路漫漫其修遠兮,吾將上下而求索!!!