開篇請各位猿友允許LZ啰嗦幾句,最近一直在寫計算機系統(tǒng)原理這系列文章,也已經(jīng)下定決心要把這本書的內容寫完。主要目的其實是為了鞏固LZ的理解,另外也想把這些內容分享給猿友們,畢竟LZ覺得這些內容對程序猿的實力還是有著很大的潛在提高的。
只是這種原理性的文章寫起來相對復雜與繁瑣,較對起來也比較困難,因為文章里充斥著各種各樣的數(shù)學符號,不過相對于這樣的寫作難度來說,其受歡迎程度,卻遠遠比不上一些難度較低的雜文。這一點從LZ的博客就能很明顯的看出,LZ博客排名前幾的文章,幾乎全部都是LZ寫的一些雜談,比如經(jīng)歷、建議、感悟等等這一類的。
不過LZ也很理解這種現(xiàn)象,畢竟雜文看起來不怎么需要動腦子,內容相對來說也比較有趣,而且說不定偶爾也能有意外的大收獲,受歡迎自是無可厚非的。不過對于計算機系統(tǒng)原理這種文章來說,倘若各位猿友能夠堅持看下去的話,應該是會有不少的收獲的。
此外LZ也希望各位猿友在觀看之余,也不妨給予LZ一些鼓勵和支持,這樣不僅LZ的動力會大大增加,也會由于猿友們的鼓勵而產(chǎn)生更大的責任感,從而更加費心的將內容更簡單的解釋清楚。
廢話就到此結束吧,再寫下去的話估計有猿友要忍不住吐槽LZ廢話連篇了。就此打住,其實說了這么多,LZ就是想說五個字,“點個推薦吧。”
引言
在上一章中,我們著重介紹了整數(shù)的表示方式,也就是無符號編碼和補碼編碼。本次我們來看一下二進制整數(shù)的擴展與截斷,這部分內容是與C語言掛鉤介紹的。因此我們首先來簡單的看一下C語言的有符號數(shù)和無符號數(shù)。
C語言中的有符號數(shù)和無符號數(shù)
有符號數(shù)和無符號數(shù)的本質區(qū)別其實就是采用的編碼不同,前者采用補碼編碼,后者采用無符號編碼。
在C語言中,有符號數(shù)和無符號數(shù)是可以隱式轉換的,不需要手動實施強制類型轉換。不過也正是因為如此,可能你不小心將一個無符號數(shù)賦給了有符號數(shù),就會造成出乎意料的結果,就像下面這樣。
#include <stdio.h>
int main(){
short i = -12345;
unsigned short u = i;
printf("%d %d\n",i,u);
}
一個不小心,一個負數(shù)就變成正數(shù)了,再看下面這個程序,它展示了在進行關系運算時,由于有符號數(shù)和無符號數(shù)的隱式轉換所導致的違背常規(guī)的結果。
#include <stdio.h>
int main(){
printf("%d\n",-1 < 0U);
printf("%d\n",-12345 < 12345U);
}
可以看到,兩個結果都為0,也就是false,這與我們直觀的理解是違背的,原因就是因為在比較的過程中,有符號數(shù)被隱式的轉換成了無符號數(shù)進行比較。
擴展
當我們將一個短整型的變量轉換為整型變量時,就涉及到了位的擴展,此時由兩個字節(jié)擴充為四個字節(jié)。
在進行位的擴展時,最容易想到的就是在高位全部補0,也就是將原來的二進制序列前面加入若干個0,也稱為零擴展。還有一種方式比較特別,是符號擴展,也就是針對有符號數(shù)的方式,它是直接擴展符號位,也就是將二進制序列的前面加入若干個最高位。
對于零擴展來說,很明顯擴展之后的值與原來的值是相等的,而對于符號擴展來說,則是一樣,只不過沒有零擴展來的直觀。我們在計算補碼時有一個比較簡單的辦法,就是符號位若為0,則與無符號是類似的。若符號位為1,也就是負數(shù)時,可以將其余位取反最終再加1即可。因此當我們對一個有符號的負數(shù)進行符號擴展時,前面加入若干個1,在取反之后都為0,因此依舊會保持原有的數(shù)值。
總之,在對位進行擴展時,是不會改變原有數(shù)值的。
在書中對于負數(shù)的符號擴展還給出了這一過程的證明,LZ這里就不多做敘述了,其實這個證明很簡單,就是利用了補碼編碼的公式而已。需要多提一句的是,這里使用了歸納法證明,因此這里只是擴展了一位,具體過程如下。
截斷
截斷與擴展相反,它是將一個多位二進制序列截斷至較少的位數(shù),也就是與擴展是相反的過程。
根據(jù)我們的直觀判斷也不難發(fā)現(xiàn),截斷可能會導致數(shù)據(jù)的失真。對于無符號編碼來說,截斷后就是剩余位數(shù)的無符號編碼數(shù)值。在書中給出了這一簡單過程的證明,它主要是想表明截斷前與截斷后的數(shù)值的關系是取模所得到的。
對于補碼編碼來說,截斷后的二進制序列與無符號編碼是一樣的,因此我們只需要多加一步,將無符號編碼轉換為補碼編碼就可以了。
因此對于無符號編碼和補碼來說,可以得到以下兩個公式。
其它語言中的有符號與無符號
從上面的分析不難看出,具有有符號和無符號數(shù)的語言,可能會因此引起一些不必要的麻煩,而且無符號數(shù)除了能表示的最大值更大以外,似乎并沒有太大的好處。因此有很多語言是不支持無符號數(shù)的。
比如LZ所使用的Java語言,就只有有符號數(shù),這樣省去了很多不必要的麻煩。無符號數(shù)很多時候只是為了表示一些無數(shù)值意義的標識,比如我們的內存地址,此時的無符號數(shù)就有點類似于數(shù)據(jù)庫主鍵或者說鍵值對中的鍵值的概念,僅僅是一個標識而已。
文章小結
本文主要闡述了C語言當中的有符號數(shù)和無符號數(shù),以及低位轉高位的擴展、高位轉低位的截斷運算,下一章我們將講解很重要的一節(jié)內容,整數(shù)的二進制運算。