在《計算機(jī)眼里的數(shù)字》這篇文章中,我曾提到,字節(jié)是計算機(jī)最小的可尋址的單位,地址對應(yīng)的是1個個字節(jié),而不是字節(jié)的每一個位。這樣編址的緣由很簡單――單個的位所能表示的信息量太少了,只有兩種狀態(tài)0和1,只有把足夠多的位組合起來才能表示足夠豐富的信息。那末為何1定要是8呢?由于大家都這么做。。。好吧,肯定1定的歷史緣由,我就不深究了。
但是,即便是8個位組成的字節(jié),其所能表示的信息量依然是有限的,由于最多只有256中狀態(tài)組合,如果用每種狀態(tài)對應(yīng)0~255之間的數(shù)字的話,那末就沒法表示256這個數(shù)。這時候候只好用兩個字節(jié)來表示大于255的數(shù)。一樣的道理,當(dāng)數(shù)字大到超過兩個字節(jié)所能表示的數(shù)的極限后,就用4個字節(jié)。。。是的,你也發(fā)現(xiàn)了,字節(jié)數(shù)目總是翻倍增長,為何不用3個字節(jié)呢?乃至,為啥不用1.5個字節(jié)呢?對前者,是由于斟酌到對齊的緣由,這其中有太多東西要說,我就不展開了;而后者,前面其實說到了,由于沒有位的編址,沒法深入到字節(jié)內(nèi)部把數(shù)據(jù)揪出來。。所以,存儲肯定會有1定的浪費,在所難免。
上面羅嗦了那末多,其實只是為了引出本文的豬腳――C語言數(shù)據(jù)類型,為何C語言要分那末多類型呢?由于對不同大小的數(shù),所需要的存儲空間大小不同。如果都用4個字節(jié)存儲,那末肯定不用分?jǐn)?shù)據(jù)類型,但是好浪費哦~所以,本著節(jié)省內(nèi)存的斟酌,數(shù)據(jù)類型就誕生了。C的數(shù)據(jù)類型分為基本數(shù)據(jù)類型和復(fù)合數(shù)據(jù)類型,后者只是前者的某種組合?;緮?shù)據(jù)類型依照其在計算機(jī)中的存儲方式又分為整數(shù)類型和浮點數(shù)類型。
1、整數(shù)類型
整數(shù)類型包括char、short、int、long、long long,它們沒有小數(shù)部份。char雖然是字符類型,但是由于存儲的是ASCII碼,本質(zhì)上也是按整數(shù)存儲的,所以歸為這1類。不同的整數(shù)類型具有不同的字節(jié)數(shù),從而所占用的存儲空間不同。但是,這1點是不肯定的,準(zhǔn)確的字節(jié)數(shù)依賴于具體的機(jī)器和編譯器――機(jī)器不但分品牌,還有32位和64位之分。下面的表格給出不同類型所占有的典型的字節(jié)數(shù)(來源《深入理解計算機(jī)系統(tǒng)》):
類型 | 32位機(jī)器 | 64位機(jī)器 |
char | 1 | 1 |
short | 2 | 2 |
int | 4 | 4 |
long | 4 | 8 |
long long | 8 | 8 |
char * | 4 | 8 |
float | 4 | 4 |
double | 8 | 8 |
注意,上表只是典型值,以32位為例:在有的機(jī)器上,short和int都是2個字節(jié),long是4個字節(jié);而有的機(jī)器上,short是2個字節(jié),而int和long是4個字節(jié)。C語言僅僅規(guī)定:short <= int <= long,然后char是1個字節(jié)。不過,對大部份機(jī)器,上表夠用了。要查看自己機(jī)器上每種類型所占的字節(jié)數(shù),請用sizeof(類型)來查看。
對整數(shù)類型,C還用了signed和unsigned來修飾它們,以取得有符號數(shù)和無符號數(shù),缺省時,認(rèn)為是有符號數(shù)。正如在《計算機(jī)眼里的數(shù)字》中提到的那樣,有符號數(shù)和無符號數(shù)的2進(jìn)制表示多是1樣的,區(qū)分僅僅是解讀方式。
有了各種類型以后(即字節(jié)數(shù)肯定以后),就能夠規(guī)定它們所表示的數(shù)的范圍。下表是32位機(jī)器各種類型的典型取值范圍:
signed | unsigned | |
char | ⑴28 ~ 127 | 0 ~ 255 |
short | ⑶2768 ~ 32767 | 0 ~ 65535 |
int | ⑵147483648 ~ 2147483647 | 0 ~ 4294967295 |
long | ⑵147483648 ~ 2147483647 | 0 ~ 4294967295 |
long long | ⑼223372036854775808 ~ 9223372036854775807 | 0 ~ 18446744073709551615 |
這些界限值可以通過包括limits.h頭文件加以查看,比如對int值的各種范圍,可以通過打印INT_MAX INT_MIN
UINT_MAX UINT_MIN 來查看。
我們用幾個例子來看1下相同類型之間signed和unsigned的轉(zhuǎn)換。
1、將signed強(qiáng)迫轉(zhuǎn)換成unsigned:
運行結(jié)果以下:
可以明顯的看出,將1個負(fù)數(shù)強(qiáng)迫轉(zhuǎn)換為無符號數(shù),并沒有改變其位模式(2進(jìn)制表示),它依然依照原來的樣子存儲,第4行的結(jié)果證明了這1點;而前3行的結(jié)果表明,即便不做signed到unsigned的強(qiáng)迫類型轉(zhuǎn)換,只需要在打印時改變1下輸出格式,就可以到達(dá)一樣的效果。(這里我開始懷疑把1個變量聲明為unsigned有啥意義?)
而將1個有符號的正數(shù)轉(zhuǎn)換為同類型的無符號數(shù)又如何呢?
2、將unsigned強(qiáng)迫轉(zhuǎn)換成signed:
那如果正數(shù)的范圍超過了TMax呢?
結(jié)果:
注意:由于變量分為signed和unsigned,對應(yīng)的常量也要分為signed和unsigned;類型前沒有修飾時,默許為signed,對應(yīng)的,1個常量數(shù)字默許為signed,即有符號數(shù)。如果希望1個常量數(shù)字被當(dāng)做無符號數(shù),就要在其末尾添加字母'u'或‘U’。