我想你一定看到過類似這樣的程式碼
((size) + ALIGNMENT - 1) & ~(ALIGNMENT-1))
看字大致意思是要記憶體對齊,但也不明白為為什麼寫成這樣?
在計算機中主存按一個傳送單位(32/64/128位)進行存取,按位元組編址
如果傳送單位為32位,也就意味著第0-3位元組能同時讀寫,第4-7位元組能同時讀寫。
如果需要讀寫3-6位元組的資料,則計算機需要分別讀兩次(0-3 4-7),無法直接讀取3-6位元組的資料
總而言之,對齊的粒度一定是2的n次方這種形式,在二進位制表示下一定會長成這樣(1後面跟著n個0):
000100...00
假設我們要分配的變數需要size
大小的空間。
要想資料不出現橫跨兩個傳送單位的尷尬情況,我們必須按照傳送單位的整數倍去分配記憶體。
size & ~(ALIGNMENT - 1)
這裡的ALIGNMENT
根據自己的需求和硬體平臺變動
現在先假定有宣告
#define ALIGNMENT 4 // 4位元組對齊
(ALIGNMENT - 1)
這一塊為0011
,取反之後為1100
,相當於掩碼,最後兩位會被置為0。這樣就得出來的數一定是ALIGNMENT
(本例中是4)的整數倍
現在我們已經知道了~(ALIGNMENT-1)
是為了取整
請你算一下如果size=3
按照size & ~(ALIGNMENT - 1)
來算的話記憶體怎麼分配
0011 & 1100 = 0
這顯然是錯的,所以我們得加上 ALIGNMENT - 1
來確保當size<ALIGNMENT
時也能得到正確結果。
為什麼不是加上ALIGNMENT
呢?
-
~(ALIGNMENT - 1)
是把低n位清零,我們將低n位先填滿這樣當size>0
時會進行向上取整 -
如果是加ALIGNMENT,當
size=ALIGNMENT
時我們會多申請一個記憶體單元
所以最後的表示式為:
((size) + ALIGNMENT - 1) & ~(ALIGNMENT-1))
size | size & ~(ALIGNMENT - 1) | ((size) + ALIGNMENT - 1) & ~(ALIGNMENT-1)) |
---|---|---|
0 | 0 | 0 |
3 | 0(錯誤) | 4 |
4 | 8(多分配了不必要的記憶體) | 4 |