結構體位元組對齊能減少記憶體占用,提高記憶體訪問效率。不論在x86或arm處理器上c的每種型別儲存都會要求記憶體對齊,除char
以外。結構體中不能包含結構體本身,但可以包含指標。由於平台原因對齊大小不同,可能同乙個結構體得到的大小會不同,但一般的對齊規則如下:
chars
可以從任何位元組位址開始,2位元組shorts
必須從偶數字址開始,4位元組的ints
或floats
必須從被4整除的位址開始,而8位元組的longs
或doubles
必須從被8整除的位址開始。
從偏移量為0的位址處開始,盡量按照同型別儲存,減少記憶體的空白。
結構體總大小為所有成員中最大對齊數的整數倍。
如果巢狀了結構體,結構體的整體大小是包括巢狀結構體的成員在內的所有最大對齊數的整數倍(可以想成把巢狀結構體inline)。
在64位amd機器上,對於如下結構體:
struct t
;int
main()
char佔1位元組,int佔4位元組,double佔8位元組,但結構體大小並不是1+4+8=13
,而是16
,原因是:char存放於開始佔1位元組,int是佔4位元組的,根據規則他只能存放在4的倍數的位址,因此存放在4號位址,同理double剛好接著在8號位址存放,至此,再看當前結構體大小是不是最大對齊數8的整數倍,是則為當前結構體不小,不是整數倍則調整為整數倍。示意如下:
在64位amd機器上,假設如下帶有巢狀結構體的結構體:
struct si
;struct t
;int
main()
執行以上**得到結果:24 40。
按照對齊規則,第乙個結構體的起始位址存放pot,or從8號位置開始儲存,因為它正好存放在它的倍數的位址上,此時儲存到12號位址,但是*x需要從它的倍數字址16號位址開始儲存8位元組到24,24正好也是最大對齊數8的整數倍,所以第乙個結構體的大小為24。對於第二個結構體同理,str存放起始位址,指標8位元組從8號位址存放到16號位址,s接著存放,所以大小為40。
如上所示的結構體struct t
,它一開始儲存較小的資料型別,然後儲存較大的資料型別,導致中間產生很多的空白空間,對於一些結構體的整體大小也會變大,解決這種問題最簡單的方式就是進行reorder
,使所有與指標對齊的字段都放在首位,在64位機器上,它們將是8個位元組,然後是4位元組的型別,然後是2位元組的型別,最後是字元型別。
對於以下結構體f,對其進行reorder之後得到的結構體f_reorder:
struct f
;struct f_reorder
;int
main()
執行以上**得到結果:32 24。
進行reorder
之後結構體整體大小變小,而且在記憶體的儲存填充的更好。reorder
也不是總能帶來正收益,比如reorder之後可能打亂了冷熱的結構,反而帶來了負收益,此時需要結合structure進行split
或是peeling
等操作。
了解關於結構體布局優化相關的內容,可參考:編譯優化之 - 結構資料布局優化入門
references:
struct記憶體對齊
出於速度和空間的考量,編譯器在實現過程中均會採用對struct內的變數進行記憶體對齊的操作,雖然會有一定的空間浪費,卻可以減少在讀取資料時候的讀取操作。先看下面的例子 struct a int main struct b int main struct b int main struct a str...
struct記憶體對齊
關於c 中的struct記憶體對齊,應該也是初學者比較疑惑的乙個知識點,但是搞清楚之後會發現非常簡單,這裡解釋一下struct記憶體到底怎麼對齊。主要記住以下兩點 1.各成員變數存放的起始位址相對於結構的起始位址的偏移量必須為該變數的型別所占用的位元組數的倍數 2.整個struct的記憶體大小需為s...
struct 記憶體對齊
struct 是一種復合資料型別,其構成元素既可以是基本資料型別 如 int long float 等 的變數,也可以是 一些復合資料型別 如 array struct union 等 的資料單元。對於結構體,編譯器會自動進行成員變數的對齊,以提高運算效率。預設情況下,編譯器為結構體的每個成員按其自...