C語(yǔ)言是一種高級(jí)語(yǔ)言,在大多數(shù)情況下C語(yǔ)言的代碼是和具體的處理器體系結(jié)構(gòu)無關(guān)的。然而,在嵌入式系統(tǒng)的編程中,有可能涉及對(duì)內(nèi)存的具體操作。在大小端和內(nèi)存對(duì)齊問題上,C語(yǔ)言就不能屏蔽不同體系結(jié)構(gòu)處理器的差別,也就是說同樣的C語(yǔ)言代碼在不同的體系結(jié)構(gòu)的處理器上,有可能產(chǎn)生不同的結(jié)果。
大小端問題又叫字節(jié)序的問題。在各種體系結(jié)構(gòu)的處理器中,對(duì)多字節(jié)數(shù)據(jù)的內(nèi)存操作有著不同的定義。處理器對(duì)內(nèi)存數(shù)據(jù)的操作有讀寫兩種,這就涉及處理器在讀寫一個(gè)多字節(jié)的內(nèi)存的時(shí)候,高字節(jié)是在內(nèi)存的高地址還是低地址。一般在32位或者16位的處理器中,都具有將32位數(shù)據(jù)和16位數(shù)據(jù)讀寫到內(nèi)存中的指令,這時(shí)不同的大小端模式將有不同的結(jié)果。
如果讀寫指令針對(duì)的數(shù)據(jù)長(zhǎng)度和類型是一致的,無論數(shù)據(jù)在內(nèi)存中存放的形式如何,處理器整體讀寫都沒有問題。這種整內(nèi)存協(xié)調(diào)的讀寫操作問題,一般不會(huì)涉及處理器的大小端。
當(dāng)處理器讀寫指令針對(duì)的數(shù)據(jù)長(zhǎng)度不一致的時(shí)候就會(huì)涉及大小端的問題,例如:
將0x76543210整體放入內(nèi)存,然后在內(nèi)存的首地址用單字節(jié)讀取的命令讀出。
如果不知道大小端模式的情況下,讀取的值是多少你能確定嗎?
這時(shí)就涉及處理器是大端還是小端的問題。
對(duì)于小端處理器,寫內(nèi)存的時(shí)候會(huì)將內(nèi)存低地址處放入源數(shù)據(jù)的低字節(jié),在內(nèi)存的高地址處放入源數(shù)據(jù)的高字節(jié);讀內(nèi)存的時(shí)候,將內(nèi)存中低地址的數(shù)據(jù)就視為目標(biāo)數(shù)據(jù)的低字節(jié),對(duì)應(yīng)的高地址數(shù)據(jù)是目標(biāo)數(shù)據(jù)的高字節(jié)。
對(duì)于大端處理器,跟小端就相反的。內(nèi)存低地址存放數(shù)據(jù)的高字節(jié),高地址存放數(shù)據(jù)的低字節(jié)。
上面的示例只是處理器自身讀取和寫入內(nèi)存的情況,在更多的情況下,內(nèi)存中的數(shù)據(jù)可能來自外界的輸入,例如:來自網(wǎng)絡(luò)的數(shù)據(jù)包;處理器在寫內(nèi)存的時(shí)候,這塊內(nèi)存也可能是給系統(tǒng)中別的設(shè)備使用的,例如:處理器寫顯示內(nèi)存的情況。這時(shí),就更需要注意處理器的大小端問題,只有大小端處理協(xié)調(diào)匹配,才能獲得正確的結(jié)果。
在C語(yǔ)言中,使用指針就可以操作內(nèi)存,指針的基本類型long和short分別代表了32位和16位的數(shù)據(jù)。使用16位或32位指針操作內(nèi)存的時(shí)候,同樣涉及內(nèi)存的大小端問題。
上面我們說了一下內(nèi)存讀寫的模式不同,一個(gè)地址存的數(shù)據(jù)不同。
接下來我們說一下內(nèi)存對(duì)齊的問題,有人會(huì)說了內(nèi)存對(duì)齊不對(duì)齊還需要你來管嗎?這個(gè)在寫程序的時(shí)候也是有講究的,那么到底什么是內(nèi)存對(duì)齊?為什么要有這個(gè)概念呢,我們來一起學(xué)習(xí)一下吧。
內(nèi)存對(duì)齊操作的含義是:對(duì)于一個(gè)4字節(jié)的數(shù)據(jù),要求其內(nèi)存是4字節(jié)對(duì)齊的(地址為4字節(jié)的整數(shù)倍)。32位對(duì)齊的含義是其內(nèi)存的地址的最低位是:0x0,0x4,0x8,0xC
16位對(duì)齊的含義是其內(nèi)存的地址的最低位是:0x0,0x2,0x4,0x6,0x8,0xA,0xC,0xE
顯然,對(duì)于單字節(jié)的內(nèi)存讀寫操作,沒有內(nèi)存對(duì)齊的問題。從處理器硬件的角度,處理器更適合處理對(duì)齊的內(nèi)存操作。對(duì)于非對(duì)齊的內(nèi)存操作,不同的處理器則有不同的結(jié)果。
局部變量建立在棧空間上的,由編譯器分配,一般保證它們都是對(duì)齊的。但是在程序中可能出現(xiàn)不對(duì)齊的內(nèi)存操作。對(duì)于嵌入式系統(tǒng)中常用的ARM體系結(jié)構(gòu),并不支持不對(duì)齊的地址操作,當(dāng)進(jìn)行不對(duì)齊的地址訪問的時(shí)候,處理器將引發(fā)異常。
在嵌入式程序的編寫過程中,更需要注意內(nèi)存對(duì)齊的問題。對(duì)于內(nèi)存操作,使用字節(jié)操作(8bit)不會(huì)有內(nèi)存對(duì)齊的問題,但是效率比較低。在32位系統(tǒng)中,應(yīng)該盡量使用32位的數(shù)據(jù)操作,但這將帶來內(nèi)存對(duì)齊的問題,因此需要根據(jù)系統(tǒng)的具體情況選擇合適的內(nèi)存操作。
我們?cè)賮碚f說常糾結(jié)或者容易迷惑的結(jié)構(gòu)體成員的對(duì)齊問題。
結(jié)構(gòu)體是一個(gè)基本的語(yǔ)法單元。在32位系統(tǒng)中,編譯器一般會(huì)對(duì)結(jié)構(gòu)體的成員變量作一定的對(duì)齊處理。例如,在程序中定義如下結(jié)構(gòu)體:
typedef struct _S1
{
char m1;
int m2;
char m3;
short m4;
}S1;
在結(jié)構(gòu)體的定義上,結(jié)構(gòu)體的大小應(yīng)該是各個(gè)結(jié)構(gòu)體成員的大小之和。但是,對(duì)于上面這個(gè)結(jié)構(gòu)體S1,它的大小并不等于4個(gè)成員變量之和。在這種定義中,三個(gè)成員變量之和是1+4+2+2=8,但是結(jié)構(gòu)體的大小并不是8字節(jié)。
編譯器在處理結(jié)構(gòu)體的時(shí)候,默認(rèn)將結(jié)構(gòu)體內(nèi)部各個(gè)變量的內(nèi)存都是對(duì)齊的,由此在結(jié)構(gòu)體的內(nèi)部可能出現(xiàn)一些空的字節(jié)。
一般情況下,在結(jié)構(gòu)體含有4字節(jié)長(zhǎng)整型成員的時(shí)候,結(jié)構(gòu)體的大小將是4字節(jié)的倍數(shù)。為了對(duì)齊可能需要在結(jié)構(gòu)體的最后補(bǔ)充1~3個(gè)字節(jié)。
如果結(jié)構(gòu)體中含有2字節(jié)短整型成員的時(shí)候,結(jié)構(gòu)體的大小將是2字節(jié)的倍數(shù)。為了對(duì)齊可能需要在結(jié)構(gòu)體的最后補(bǔ)充一個(gè)字節(jié)。
這個(gè)算字節(jié)數(shù)的一般出現(xiàn)在找工作中的筆試題的概率還是很高的,其實(shí)就是考察的對(duì)這個(gè)內(nèi)存對(duì)齊的掌握。
責(zé)任編輯:haq
-
嵌入式
+關(guān)注
關(guān)注
5082文章
19126瀏覽量
305249 -
C語(yǔ)言
+關(guān)注
關(guān)注
180文章
7604瀏覽量
136842
原文標(biāo)題:在嵌入式系統(tǒng)中大小端和對(duì)齊問題
文章出處:【微信號(hào):CanaanTech,微信公眾號(hào):嘉楠科技】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論