主題:CPU的架構(gòu)決定了大端小端模式和棧的生長方向。 前天參加深信服的專場招聘,問到不定參數(shù)函數(shù)的實現(xiàn),當(dāng)時只記得參數(shù)入?yún)⑹菑挠业阶螅窃跅V械拇娣诺刂反笮‘?dāng)時就想不起來了,現(xiàn)在專門好好整理一下。 首先參數(shù)從右到左壓棧的方式,這是C語言決定的,比如說Pascal就是從左到右壓棧,所以Pascal不支持不定參數(shù)函數(shù)。比如:
格式字符串是確定存在的,后面的變量都是不確定的或者說不知道有多少個。如果格式字符串最后一個入棧,位于棧頂,第一個出棧然后解析格式字符串得到不定參的個數(shù),挨個出棧,這樣就很方便。Pascal語言不支持可變長參數(shù),而C語言支持這種特色,正是這個原因使得C語言函數(shù)參數(shù)入棧順序為從右至左。C方式參數(shù)入棧順序(從右至左)的好處就是可以動態(tài)變化參數(shù)個數(shù)。通過棧分析可知,自左向右的入棧方式,最前面的參數(shù)被壓在棧底。除非知道參數(shù)個數(shù),否則是無法通過棧指針的相對位移求得最左邊的參數(shù)。這樣就變成了左邊參數(shù)的個數(shù)不確定,正好和動態(tài)參數(shù)個數(shù)的方向相反。 這里其實還涉及到C語言中調(diào)用約定所采用的方式:
這里第一個得到格式字符串的地址之后,后面的不定參數(shù)的地址是比這個大還是小了?這就是棧的生長方式?jīng)Q定的,51的棧是向高地址增長,INTEL的8031、8032、8048、8051系列使用向高地址增長的棧。但同樣是INTEL,在x86系列中全部使用向低地址增長的棧。其他公司的CPU中除ARM的結(jié)構(gòu)提供向高地址增長的棧選項外,多數(shù)都是使用向低地址增長的棧。順便提一下,x86使用的向高地址增長的堆,符合我們的使用習(xí)慣。 也就是說x86中,棧底是高地址,棧頂是低地址,先入棧到高地址的棧底,然后到低地址的棧頂。所以不定參數(shù)的地址比格式字符串的地址大。這樣設(shè)計可以使得堆和棧能夠充分利用空閑的地址空間。如果棧向上漲的話,我們就必須得指定棧和堆的一個嚴(yán)格分界線,但這個分界線怎么確定呢?平均分?但是有的程序使用的堆空間比較多,而有的程序使用的棧空間比較多。所以就可能出現(xiàn)這種情況:一個程序因為棧溢出而崩潰的時候,其實它還有大量閑置的堆空間呢,但是我們卻無法使用這些閑置的堆空間。所以呢,最好的辦法就是讓堆和棧一個向上漲,一個向下漲,這樣它們就可以最大程度地共用這塊剩余的地址空間,達到利用率的最大化!
所謂的大端模式,是指數(shù)據(jù)的低位保存在內(nèi)存的高地址中,而數(shù)據(jù)的高位,保存在內(nèi)存的低地址中; 所謂的小端模式,是指數(shù)據(jù)的低位保存在內(nèi)存的低地址中,而數(shù)據(jù)的高位保存在內(nèi)存的高地址中。 所以數(shù)據(jù)之間的地址大小看棧的生長方式,數(shù)據(jù)內(nèi)的地址大小看大小端模式。在計算機系統(tǒng)中,我們是以字節(jié)為單位的,每個地址單元都對應(yīng)著一個字節(jié),一個字節(jié)為8bit。但是在C語言中除了8bit的char之外,還有16bit的short型,32bit的long型(要看具體的編譯器),另外,對于位數(shù)大于8位的處理器,例如16位或者32位的處理器,由于寄存器寬度大于一個字節(jié),那么必然存在著一個如果將多個字節(jié)安排的問題。因此就導(dǎo)致了大端存儲模式和小端存儲模式。 這里引出主機字節(jié)序和網(wǎng)絡(luò)字節(jié)序,主機字節(jié)序是由CPU決定的,也就是大小端。我們常用的x86結(jié)構(gòu)是小端模式。網(wǎng)絡(luò)字節(jié)序是固定的,就是大端模式,網(wǎng)絡(luò)字節(jié)序這是TCP/ip協(xié)議中定義好的一種數(shù)據(jù)格式,它是與你的機器的CPU,操作系統(tǒng)什么的無關(guān)的,這樣可以保證數(shù)據(jù)在網(wǎng)絡(luò)中傳輸時,不管怎么樣都能正確的解釋!所以就有了網(wǎng)絡(luò)字節(jié)序到本機字節(jié)序和本機字節(jié)序到網(wǎng)絡(luò)字節(jié)序的轉(zhuǎn)換: htons:把unsigned short類型從主機序轉(zhuǎn)換到網(wǎng)絡(luò)序 htonl:把unsigned long類型從主機序轉(zhuǎn)換到網(wǎng)絡(luò)序 ntohs:把unsigned short類型從網(wǎng)絡(luò)序轉(zhuǎn)換到主機序 ntohl:把unsigned long類型從網(wǎng)絡(luò)序轉(zhuǎn)換到主機序 反正網(wǎng)絡(luò)字節(jié)序是固定的,這樣只要兩邊主機遵循大端模式發(fā)送出去,以大端模式來接收,就不會有問題。
新聞熱點
疑難解答