本文將首先解釋內(nèi)存訪問粒度概念,以便可以了解處理器如何訪問內(nèi)存。然后,將進一步了解數(shù)據(jù)對齊的概念,并研究一些示例結(jié)構(gòu)的內(nèi)存布局。在之前關(guān)于嵌入式C中結(jié)構(gòu)的文章中,了解到重新排列結(jié)構(gòu)中成員的順序可以改變存儲結(jié)構(gòu)所需的內(nèi)存量。還將看到編譯器在為結(jié)構(gòu)成員分配內(nèi)存時具有某些約束。這些約束被稱為數(shù)據(jù)對齊要求,允許處理器以可能出現(xiàn)在存儲器布局中的一些浪費空間(稱為“填充”)為代價來更有效地訪問變量。計算機的內(nèi)存系統(tǒng)可能比這里介紹的要復(fù)雜得多。本文的目標(biāo)是討論在編寫嵌入式系統(tǒng)時可能有用的一些基本概念。
內(nèi)存訪問粒度
我們通常將內(nèi)存設(shè)想為單字節(jié)存儲位置的集合,如圖1所示。每個位置都有一個唯一的地址,允許我們訪問該地址的數(shù)據(jù)。
圖1
但是,處理器通常以大于一個字節(jié)的塊形式訪問內(nèi)存。例如,處理器可以以四字節(jié)塊的形式訪問內(nèi)存。在這種情況下,我們可以設(shè)想圖1中的12個連續(xù)字節(jié),如下面的圖2所示。
圖2
你可能想知道這兩種處理內(nèi)存的方式之間有什么區(qū)別。使用圖1,處理器一次讀取一個字節(jié)并向內(nèi)存寫入。請注意,在讀取內(nèi)存位置或?qū)懭雰?nèi)存之前,我們需要訪問該內(nèi)存單元,并且每次內(nèi)存訪問都需要一些時間。假設(shè)我們想要讀取圖1中存儲器的前八個字節(jié)。對于每個字節(jié),處理器需要訪問內(nèi)存并讀取它。因此,為了讀取前八個字節(jié)的內(nèi)容,處理器將必須訪問內(nèi)存八次。
在圖2中,處理器一次讀取4個字節(jié)并將其寫入內(nèi)存。因此,為了讀取前四個字節(jié),處理器訪問存儲器的地址0并讀取四個連續(xù)的存儲位置(地址0到3)。同樣,要讀取下一個四字節(jié)塊,處理器需要再次訪問內(nèi)存。它轉(zhuǎn)到地址4并同時從地址4到7讀取存儲位置。對于字節(jié)大小的塊,需要8次內(nèi)存訪問來讀取連續(xù)8個字節(jié)的內(nèi)存。但是,使用圖2,只需要兩次內(nèi)存訪問。如上所述,每次內(nèi)存訪問都需要一些時間。由于圖2中所示的存儲器配置減少了訪問次數(shù),因此可以提高處理效率。處理器在訪問內(nèi)存時使用的數(shù)據(jù)大小稱為內(nèi)存訪問粒度。圖2描繪了具有四字節(jié)存儲器訪問粒度的系統(tǒng)。
內(nèi)存訪問邊界
硬件設(shè)計人員經(jīng)常采用另一種重要技術(shù)來提高處理系統(tǒng)的效率:它們限制處理器,使其只能在某些邊界訪問內(nèi)存。例如,處理器可能僅能夠在四字節(jié)邊界上訪問圖2的內(nèi)存,如圖3中的紅色箭頭所示。
圖3
這種邊界限制會使系統(tǒng)顯著提高效率嗎?仔細看看。假設(shè)我們需要讀取地址為3和4的內(nèi)存位置的內(nèi)容(由圖3中的綠色和藍色矩形表示)。如果處理器可以從任意地址開始讀取一個四字節(jié)的塊,那么我們可以訪問地址3并通過單個內(nèi)存訪問讀取兩個所需的內(nèi)存位置。但是,如上所述,處理器不能直接訪問任意地址;相反,它只在某些邊界訪問內(nèi)存。那么如果處理器只能訪問四字節(jié)邊界,它將如何讀取地址3和4的內(nèi)容?
由于內(nèi)存訪問邊界限制,處理器必須訪問地址為0的內(nèi)存位置并讀取連續(xù)的四個字節(jié)(地址0到3)。接下來,它必須使用移位操作將地址3的內(nèi)容與其他三個字節(jié)(地址0到2)分開。類似地,處理器可以訪問地址4并從地址4到7讀取另一個四字節(jié)塊。最后,可以使用移位操作將所需字節(jié)(藍色矩形)與其他三個字節(jié)分開。
如果沒有內(nèi)存訪問邊界限制,可以用一個內(nèi)存訪問讀取地址3和地址4。但是,邊界限制迫使處理器兩次訪問存儲器。那么,如果數(shù)據(jù)操作變得更加困難,為什么需要限制對某些邊界的內(nèi)存訪問呢?內(nèi)存訪問邊界存在限制,因為對地址進行某些假設(shè)可以簡化硬件設(shè)計。例如,假設(shè)一個內(nèi)存塊中的所有字節(jié)都需要32位來尋址。如果將地址限制為四字節(jié)邊界,那么32位地址中的兩個最低有效位將始終為零(因為地址始終可以被4整除)。因此,我們可以使用30位來尋址一個232字節(jié)的內(nèi)存。
數(shù)據(jù)對齊
既然已經(jīng)知道基本處理器如何訪問內(nèi)存,那么下面就可以可以討論數(shù)據(jù)對齊要求。通常,任何K字節(jié)C數(shù)據(jù)類型必須具有K的倍數(shù)的地址。例如,四字節(jié)數(shù)據(jù)類型只能存儲在地址0,4,8,中;它不能存儲在地址1,2,3,5。這些限制簡化了處理器和內(nèi)存系統(tǒng)之間的接口硬件的設(shè)計。
例如,考慮一個具有四字節(jié)內(nèi)存訪問粒度的處理器,它只能以四字節(jié)邊界訪問內(nèi)存。假設(shè)一個四字節(jié)變量存儲在地址1,如圖4所示(四個字節(jié)對應(yīng)四種不同的顏色)。在這種情況下,我們需要兩次內(nèi)存訪問和一些額外的工作來讀取未對齊的四字節(jié)數(shù)據(jù)(“未對齊”指它被分成兩個四字節(jié)塊)。該過程如圖所示。
圖4
但是,如果將一個四字節(jié)變量存儲在4的倍數(shù)的任何地址,只需要一個內(nèi)存訪問來修改數(shù)據(jù)或讀取數(shù)據(jù)。所以將K字節(jié)數(shù)據(jù)類型存儲在K的倍數(shù)的地址可以提高系統(tǒng)的效率。因此,C語言“char”變量(只需要一個字節(jié))可以存儲在任何字節(jié)地址,但是一個雙字節(jié)變量必須存儲在偶數(shù)地址中。四字節(jié)類型必須從可被4整除的地址開始,并且八字節(jié)數(shù)據(jù)類型必須存儲在可被8整除的地址。例如,假設(shè)在特定機器上,“short”變量需要兩個字節(jié),“int”和“float”類型占用四個字節(jié),“l(fā)ong”、“double”指針占用八個字節(jié)。這些數(shù)據(jù)類型中的每一種通常應(yīng)具有K的倍數(shù)的地址,其中K由下表給出。
請注意,不同數(shù)據(jù)類型的大小可能因編譯器和計算機體系結(jié)構(gòu)的不同而不同。sizeof()運算符是查找數(shù)據(jù)類型實際大小的最佳方法。
責(zé)任編輯人:CC
-
嵌入式
+關(guān)注
關(guān)注
5126文章
19446 -
C語言
+關(guān)注
關(guān)注
180文章
7628瀏覽量
139843
發(fā)布評論請先 登錄
C語言入門書籍《嵌入式Linux C語言程序設(shè)計基礎(chǔ)教程》全本下載?。?/a>
C語言中使用嵌入式SQL訪問Oracle數(shù)據(jù)庫的方法
嵌入式C語言結(jié)構(gòu)設(shè)計_實驗二
嵌入式C實現(xiàn)延時程序的不同變量的區(qū)別 幾種Linux嵌入式開發(fā)環(huán)境的簡單介紹

嵌入式C語言中如何判斷數(shù)據(jù)是否損壞

標(biāo)準(zhǔn)c語言與嵌入式,嵌入式C語言與C語言的區(qū)別

C語言嵌入式培訓(xùn) 嵌入式C語言程序設(shè)計基礎(chǔ)

嵌入式C語言知識總結(jié)

嵌入式C語言中堆和棧的區(qū)別
嵌入式C語言之堆和棧介紹
嵌入式C語言的結(jié)構(gòu)特點

評論