假如我是一條內(nèi)存
我從無邊無盡的黑暗中慢慢醒來,迷迷糊糊,茫然四顧。
耳邊傳來了風(fēng)扇賣力干活的嗡嗡聲,估計(jì)就是他把我吵醒的。 這時候 CPU阿甘 現(xiàn)身了:“兄弟,快醒醒,開機(jī)了,要干活了,我要把程序和數(shù)據(jù)從硬盤讀取到你這里來了!”
“放到我這里干嘛?”
“唉,一斷電,你什么都忘了,不把程序讀入內(nèi)存,我怎么執(zhí)行啊?”
奧,對了,我是內(nèi)存啊,阿甘是我的好朋友,雖然說程序都在硬盤上存著,但是阿甘被設(shè)計(jì)成只能運(yùn)行我內(nèi)存中的程序,所以程序必須要裝載進(jìn)來。
在這個系統(tǒng)里,阿甘最快,我第二, 硬盤則慢如蝸牛,他整天叫囂著說要提高訪問速度,到時候可以把我徹底替換掉, 但是這么多年過去了,還是沒有什么進(jìn)展。
不知道等了多長時間,阿甘終于把一個叫做Linux的操作系統(tǒng)給裝載到我這里來了,阿甘說從此以后它就是這里的老大。
可是我卻感覺不到老大的存在,我只知道我那一個個電容所代表的0和1 ,由于這些電容不能持久地保持電荷,我得定期地去刷新,如果不及時刷新,那些0和1的數(shù)據(jù)就會丟失,這將是極為嚴(yán)重的事故,主人就會把我從主板上拔掉,用另外一個家伙來替換我,決不允許這樣的事情發(fā)生!
次序問題
但是程序員們卻不管什么電容,什么刷新,在他們的眼里,我就是一個個的空格子,每個格子對應(yīng)一個地址,就像門牌號一樣。
我最小的一個格子就是一個bit ,只能存儲0和1,這實(shí)在是太小了, 人們把8個bit 稱為一個字節(jié)(Byte), 就可以表達(dá)2的8次方種可能,從00000000 到 11111111, 如果是無符號數(shù)的話,就是0~255。
很明顯,Byte還是太小,人們又把更多的字節(jié)(比如4個)組織起來,叫做一個Word(字) 。
字節(jié)數(shù)目一多,就出現(xiàn)了很有意思的問題,比如說有個整數(shù),十六進(jìn)制的值是0x1234567, 一共是四個字節(jié),那該以什么次序存儲他們呢?
一種辦法是這樣:
還有一種方法是這樣:
可笑的是人類為這兩種方式爭執(zhí)不休,有人堅(jiān)決支持大端法,有人則捍衛(wèi)第二種(即小端法),還有些和稀泥的家伙,大端小端都支持,就看你怎么選擇和配置了。
我問CPU阿甘:“如果兩個機(jī)器的字節(jié)次序不同,他們兩個通信的時候,豈不天下大亂?”
阿甘嘆息一聲:“唉,他們在制定TCP/IP的時候,確定了統(tǒng)一的網(wǎng)絡(luò)次序,使用大端法來傳輸數(shù)據(jù)。操作系統(tǒng)老大會提供特定的函數(shù)來實(shí)現(xiàn)網(wǎng)絡(luò)和主機(jī)之間字節(jié)次序的轉(zhuǎn)換,比如 htonl 函數(shù),就可以把32位整數(shù)由主機(jī)字節(jié)次序轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)次序, ntohl則恰恰相反。 ”
編譯器
剛才說到,內(nèi)存中每個字節(jié)都有一個對應(yīng)的地址,只要能記住這個地址就可以把這個字節(jié)的值給取走,或者寫入一個值。
比如說,剛才CPU阿甘執(zhí)行了一些列的指令, 它把地址0x100處的值取出來,和 0x104處的值相加,放到0x110處, 然后再和0x108處的值相乘,結(jié)果放到0x10C處。
這一系列操作搞得我眼花繚亂,我對CPU阿甘說:“這程序員真是很厲害,居然能夠記住這么多地址!”
阿甘說:“怎么可能? 他們笨得很,根本記不住,全靠了編譯器的幫忙。”
“編譯器? ”
“是啊,編譯器允許程序員用變量的方式來表達(dá)程序,它可以把這些變量轉(zhuǎn)換成地址。沒有編譯器,程序員將會像熊貓一樣少。”
- total = base + bonus
- tax = total * rate
原來如此,我這里看到的都是二進(jìn)制的值,沒想到程序員都給他們起了一個名字。
信息 = 位 + 上下文
有一次, 阿甘問我地址0x300的值是多少,我看了一眼,告訴他說是一個32位整數(shù)1735159650。
阿甘大驚失色:“兄弟,你睡了一覺什么忘了嗎, 你不能擅自去解釋你內(nèi)存數(shù)據(jù)的類型啊!”
“為什么? 這就是個整數(shù)嘛!”
“你這里的值實(shí)際上是0x 676C 6F62,他有可能是32位整數(shù)1735159650,也有可能是浮點(diǎn)數(shù) 1.116533*10^24,還有可能是機(jī)器指令呢!!記住!解釋權(quán)不在你,而在人家應(yīng)用程序那里,你就管好你電容里的'二進(jìn)制'就行!”
我覺得很羞愧,這么重要的準(zhǔn)則都給忘記了!
信息=位+上下文, 我這里只負(fù)責(zé)一串串的二進(jìn)制位,至于這些位的信息是什么,得加上下文才能理解了。
指針
過了一會兒,阿甘問我0x108處存了什么內(nèi)容, 這一次我不再“解釋”了,我告訴他是0x100。
奇怪的是他接下來又問我0x100處的值是什么, 我告訴他說是0x12C, 他這才滿意地離開。
我拉著他問道:“你這次怎么了,這么麻煩?還得讀兩次才行?”
他說:“沒辦法,程序員用指針了!”
- int i = 300;
- int *p = &i
- total = *p + 200;
“看到?jīng)]有,這個變量p就表示指針。”
我嚇了一跳:“難道我的格子里保存的不僅僅是值,而是地址?”
“是啊,這就再次證明,你不要胡亂解釋你保存的值。 我告訴你,有時候還會出現(xiàn)二級指針呢。”
- int i = 300;
- int *p = &i ;
- int **pp = &p;
這真是顛覆了我的認(rèn)知,我還是刷新我的電容去吧!
不過,在億萬次的讀寫操作中,我通過這些指針的關(guān)系,也發(fā)現(xiàn)了一些獨(dú)特的模式,比如說我發(fā)現(xiàn)這樣的東西很常見:
我問阿甘:“這是在干嘛? ”
“這就是程序員實(shí)現(xiàn)的鏈表啊。”
“ 那這個東西呢?”
阿甘說:“這不就是一顆二叉樹嘛! 程序員管這些東西叫做數(shù)據(jù)結(jié)構(gòu)。”
我原來以為,我就是一個大數(shù)組而已,沒想到通過指針,可以表達(dá)各種各樣的復(fù)雜的數(shù)據(jù)結(jié)構(gòu)的,只要你能沿著指針來回跳轉(zhuǎn)就行。
但是我心里隱隱覺得不妥,這指針實(shí)在是太強(qiáng)大了,程序員可以把它指向任何地方,我知道有些地方是操作系統(tǒng)老大的獨(dú)有區(qū)域,是嚴(yán)禁外界進(jìn)入的,萬一指針指到這里會發(fā)生什么事?
阿甘說:“這不用你操心,如果有個程序通過指針想訪問它根本沒有權(quán)限的區(qū)域,老大就會引發(fā)一個segment fault,把這個程序殺死!”
“殺死以后呢?”
“那個程序的內(nèi)存空間就會被釋放, 與此同時老大會生成一個叫做core dump的文件,讓程序員們?nèi)シ治觥?唉,今天你真是煩人,問了這么多問題。 不說了,主人要關(guān)機(jī)了,明天再見!”
風(fēng)扇停轉(zhuǎn),電流消失,整個世界安靜了。
第二天
我從無邊無盡的黑暗中慢慢醒來,迷迷糊糊,茫然四顧。
耳邊傳來了風(fēng)扇賣力干活的嗡嗡聲,估計(jì)就是他把我吵醒的。 這時候CPU阿甘現(xiàn)身了:“兄弟,快醒醒,開機(jī)了,要干活了,我要把程序和數(shù)據(jù)從硬盤讀取到你這里來了!”
.....
【本文為51CTO專欄作者“劉欣”的原創(chuàng)稿件,轉(zhuǎn)載請通過作者微信公眾號coderising獲取授權(quán)】