上一章(1.1-1.4)LZ和各位簡(jiǎn)單的探討了一下計(jì)算機(jī)系統(tǒng)中的一些基本概念,本次我們將進(jìn)入一個(gè)嶄新的世界。在1.1那一章當(dāng)中,我們已經(jīng)簡(jiǎn)單的提及了信息的概念,本次我們會(huì)逐漸深入的討論信息的相關(guān)內(nèi)容。
引言
我們很難想象,1和0這兩個(gè)再簡(jiǎn)單不過(guò)的數(shù)字,給計(jì)算機(jī)科學(xué)帶來(lái)了徹底的改變。對(duì)于無(wú)法與人腦相比的計(jì)算機(jī)來(lái)說(shuō),簡(jiǎn)單的1和0就是最適合它們的數(shù)字。不過(guò)1個(gè)1或者1個(gè)0往往代表不了任何意義,它們必須被賦予上下文,才能有具體的含義。比如,如果我們知道1和0是代表的布爾類(lèi)型的值,那么我們就知道1是true,0是false。
對(duì)于二進(jìn)制所表示的數(shù)字來(lái)說(shuō),主要有三種,即無(wú)符號(hào)、補(bǔ)碼以及浮點(diǎn)數(shù)。
由于計(jì)算機(jī)對(duì)于固定類(lèi)型的二進(jìn)制數(shù)字往往都是有位數(shù)限制的,比如int類(lèi)型使用四個(gè)字節(jié)(32位二進(jìn)制)來(lái)表示,因此在計(jì)算的時(shí)候,會(huì)發(fā)生溢出的情況,最簡(jiǎn)單的我們使用無(wú)符號(hào)整數(shù)0xFFFFFFFF與無(wú)符號(hào)整數(shù)0xFFFFFFFF相乘,則會(huì)產(chǎn)生溢出。
在產(chǎn)生溢出的時(shí)候,得出的結(jié)果往往會(huì)令人大跌眼鏡。比如兩個(gè)正數(shù)相乘可能得到負(fù)值,兩個(gè)正數(shù)相加也可能得到負(fù)值。而對(duì)于不同的計(jì)算機(jī)來(lái)說(shuō),由于數(shù)值范圍可能有所不同,因此掌握信息相關(guān)的內(nèi)容對(duì)于寫(xiě)出跨平臺(tái)的程序來(lái)講也是很有幫助的。
信息的存儲(chǔ)
大多數(shù)計(jì)算機(jī)使用8位的塊,或者說(shuō)字節(jié),來(lái)作為最小的可尋址的存儲(chǔ)器單位,而不是在存儲(chǔ)器中訪問(wèn)單獨(dú)的位。換句話說(shuō),我們?cè)谠L問(wèn)存儲(chǔ)器的內(nèi)容時(shí),最小的訪問(wèn)單位一般是字節(jié)。
在我們編程的時(shí)候,往往會(huì)把虛擬存儲(chǔ)器(virtual memory)抽象為一個(gè)字節(jié)數(shù)組,而每一個(gè)數(shù)組內(nèi)的元素或者說(shuō)字節(jié)都有唯一的地址(address),這些地址的集合就被稱(chēng)作虛擬地址空間。虛擬地址空間是為了給機(jī)器級(jí)的程序一個(gè)概念上的映像,實(shí)際上為了提供這個(gè)映像,內(nèi)部的實(shí)現(xiàn)是非常復(fù)雜的。
十六進(jìn)制表示法
對(duì)于機(jī)器來(lái)說(shuō),可能比較喜歡0和1,但是對(duì)于人類(lèi)這種高級(jí)生物來(lái)說(shuō),1和0就有點(diǎn)不夠看了。因此通常情況下,為了便于閱讀,我們會(huì)使用十六進(jìn)制去表示二進(jìn)制。1位十六進(jìn)制的數(shù)字可以表示4位二進(jìn)制數(shù)字,因此一個(gè)字節(jié)就可以表示為0x00---0xFF。
有關(guān)十六進(jìn)制、二進(jìn)制以及十進(jìn)制的轉(zhuǎn)換,LZ這里就直接略過(guò)了,相信大部分人應(yīng)該都對(duì)這個(gè)轉(zhuǎn)換并不陌生。
字
每臺(tái)計(jì)算機(jī)都有一個(gè)字長(zhǎng)(word size),用于指明整數(shù)和指針數(shù)據(jù)的標(biāo)準(zhǔn)大?。╪ominal size)。而由于虛擬地址空間中的地址就是使用一個(gè)字來(lái)表示的,因此操作系統(tǒng)中的字長(zhǎng)就決定了虛擬地址空間的大小。
比如32位操作系統(tǒng)下,最大內(nèi)存就是232 = 4 * 210 * 210 * 210 B = 4GB,而在64位操作系統(tǒng)下,LZ還專(zhuān)門(mén)問(wèn)了問(wèn)群里的猿友,最終得到的結(jié)果是234GB。
數(shù)據(jù)大小
由于計(jì)算機(jī)位數(shù)的不同,會(huì)造成在數(shù)據(jù)類(lèi)型的存儲(chǔ)上,采用的位數(shù)略有不同,下表是在32位和64位機(jī)器下,C語(yǔ)言當(dāng)中的數(shù)字?jǐn)?shù)據(jù)類(lèi)型需要的位數(shù)。
可以看出,對(duì)于長(zhǎng)整形以及字符指針類(lèi)型來(lái)說(shuō),在32位和64位系統(tǒng)下的字節(jié)數(shù)是不同的。特別的,對(duì)于指針類(lèi)型來(lái)說(shuō),所有指針類(lèi)型在32位下都是4位,而在64位下都是8位,這是由虛擬地址空間的地址位數(shù)或者說(shuō)字長(zhǎng)所決定的。
尋址和字節(jié)順序
對(duì)于跨越多個(gè)字節(jié)的程序?qū)ο螅ǔ绦驅(qū)ο笾钢噶?、?shù)據(jù)或者控制信息等,是程序當(dāng)中對(duì)象的統(tǒng)稱(chēng))來(lái)說(shuō),我們需要制定兩個(gè)規(guī)則,才能唯一確定一個(gè)程序?qū)ο蟮闹怠?/p>
比如對(duì)于int類(lèi)型的值0xFF來(lái)說(shuō),如果我們要根據(jù)虛擬內(nèi)存地址去獲取這個(gè)整數(shù)值,那么首先我們需要知道它的起始虛擬內(nèi)存地址是多少。另外,我們還需要知道,對(duì)于表示int類(lèi)型的四個(gè)字節(jié)來(lái)說(shuō),這四個(gè)字節(jié)的排列順序。
對(duì)于第一個(gè)問(wèn)題,由于大部分計(jì)算機(jī)都采用連續(xù)的內(nèi)存地址去存儲(chǔ)一個(gè)程序?qū)ο螅虼宋覀兎Q(chēng)內(nèi)存地址中最小的那個(gè)就是該程序?qū)ο蟮钠鹗嫉刂?,也是該程序?qū)ο蟮牡刂贰?/p>
對(duì)于第二個(gè)問(wèn)題,一般有兩種方式,即大端法和小端法。對(duì)于一個(gè)整數(shù)0x000000FF來(lái)說(shuō),我們假設(shè)它的起始地址為0x1,那么對(duì)于使用大端法規(guī)則的系統(tǒng)來(lái)說(shuō),0x1-0x4的虛擬內(nèi)存所存儲(chǔ)的值依次為0x00、0x00、0x00、0xFF,相反對(duì)于采用小端法規(guī)則的系統(tǒng)來(lái)說(shuō),0x1-0x4的虛擬內(nèi)存所存儲(chǔ)的值依次為0xFF、0x00、0x00、0x00。
強(qiáng)制類(lèi)型轉(zhuǎn)換
對(duì)于一個(gè)特定的數(shù)據(jù)類(lèi)型來(lái)講,計(jì)算機(jī)在解釋這類(lèi)數(shù)據(jù)的值的時(shí)候,是根據(jù)起始位置以及數(shù)據(jù)類(lèi)型的位數(shù)來(lái)確定的。比如對(duì)于無(wú)符號(hào)int類(lèi)型的數(shù)據(jù)來(lái)說(shuō),倘若我們知道它的起始位置為0x1,而當(dāng)前的操作系統(tǒng)采取的是大端法規(guī)則,假設(shè)0x1-0x4的內(nèi)存地址中存儲(chǔ)的字節(jié)依次為0xFF,0xFF,0xFF,0xFF,由此計(jì)算機(jī)將會(huì)幫我們計(jì)算出這個(gè)無(wú)符號(hào)int類(lèi)型的值為232-1,也就是無(wú)符號(hào)int類(lèi)型的最大值。
這其中計(jì)算機(jī)是根據(jù)0x1-0x4這四個(gè)字節(jié)上的值,以及無(wú)符號(hào)int類(lèi)型的解釋方式,最終得到的這個(gè)無(wú)符號(hào)int類(lèi)型的值。
由此可見(jiàn),計(jì)算機(jī)在解釋一個(gè)數(shù)據(jù)類(lèi)型的值時(shí)主要有四個(gè)因素:位排列規(guī)則(大端或者小端)、起始位置、數(shù)據(jù)類(lèi)型的字節(jié)數(shù)、數(shù)據(jù)類(lèi)型的解釋方式。
對(duì)于特定的系統(tǒng)來(lái)說(shuō),前兩種因素都是特定的,而對(duì)于后兩種因素的改變,則可以改變一個(gè)數(shù)據(jù)類(lèi)型的值的最終計(jì)算結(jié)果,這就是強(qiáng)制類(lèi)型轉(zhuǎn)換。對(duì)于大部分高級(jí)程序設(shè)計(jì)語(yǔ)言來(lái)講,都提供了強(qiáng)制類(lèi)型轉(zhuǎn)換。
比如C語(yǔ)言,我們可以將一個(gè)無(wú)符號(hào)int類(lèi)型的值強(qiáng)制轉(zhuǎn)換為其它類(lèi)型,在轉(zhuǎn)換之后,對(duì)于上面四個(gè)因素之中,改變的是最后兩個(gè)。為此我們寫(xiě)一個(gè)小程序來(lái)看下這個(gè)有意思的事情。
#include <stdio.h>
int main(){
unsigned int x = 0xFFFFFF61;
int *p = &x;
char *cp = (char *)p;
printf("%c\n",*cp);
}
這是一個(gè)簡(jiǎn)單的強(qiáng)制類(lèi)型轉(zhuǎn)換示例,可以看到我們將一個(gè)無(wú)符號(hào)int類(lèi)型的值,先賦給了一個(gè)int類(lèi)型的指針,又強(qiáng)制轉(zhuǎn)換成了char類(lèi)型的指針,最終我們輸出這個(gè)char類(lèi)型指針?biāo)淼淖址?,結(jié)果的輸出是一個(gè)a。
輸出a的原因就是由上面的四個(gè)因素決定的,我們看這個(gè)具體程序上的四個(gè)因素。
1、cp指針的值與x變量的起始內(nèi)存地址相等。(起始位置)
2、LZ的linux系統(tǒng)是小端表示法,也就是說(shuō)假設(shè)x變量的起始內(nèi)存地址為0x1,那么0x1-0x4的值分別為0x61、0xFF、0xFF、0xFF。(位排列規(guī)則)
3、char只占一個(gè)字節(jié),因此會(huì)只讀取0x61這個(gè)值。(數(shù)據(jù)類(lèi)型的字節(jié)數(shù),或者說(shuō)大?。?/p>
4、0x61為十進(jìn)制的97,對(duì)應(yīng)ascii表的話,代表的是字符a,因此最終輸出了a。(數(shù)據(jù)類(lèi)型的解釋方式)
可以看出,強(qiáng)制類(lèi)型轉(zhuǎn)換有時(shí)候會(huì)讓結(jié)果變的讓人難以預(yù)料,因此這種技巧一般不太推薦使用,但是這種手段也確實(shí)是程序設(shè)計(jì)語(yǔ)言所必需的。
字符串的表示
這一點(diǎn)其實(shí)上面我們已經(jīng)提到了,我們知道97其實(shí)代表的是字符'a',而這個(gè)的由來(lái)就是根據(jù)ascii表來(lái)的,我們?cè)趌inux系統(tǒng)上可以輸入man ascii命令來(lái)查看。
代碼的表示
二進(jìn)制如何表示代碼?
其實(shí)這些都是編譯器的責(zé)任了,我們只需要寫(xiě)出像上面那個(gè)小程序一樣的人們可以看懂的代碼,編譯器便會(huì)幫我們將其翻譯成對(duì)應(yīng)的機(jī)器所認(rèn)識(shí)的二進(jìn)制序列。從這個(gè)角度上來(lái)講,程序語(yǔ)言其實(shí)就是一個(gè)二進(jìn)制序列的簡(jiǎn)單描述,它提供我們更簡(jiǎn)單的編寫(xiě)計(jì)算機(jī)可以執(zhí)行的二進(jìn)制序列的方式。
文章小結(jié)
本次我們初步探索了信息的存儲(chǔ)以及信息所代表的結(jié)果的計(jì)算,這些內(nèi)容都比較基礎(chǔ),相信不難看懂。