結構體內部儲存中的對齊問題

2021-07-23 17:35:25 字數 1752 閱讀 5902

我們考慮如下的這個結構體:

struct align ;
如果某個機器的整型值長度為4個位元組,並且它的起始儲存位置必須能夠被4整除,那麼這個結構體在記憶體中的儲存將如下圖所示:

說明:系統禁止編譯器在乙個結構體的起始位置跳過幾個位元組來滿足邊界的對齊要求,因此所有結構體的起始儲存位置必須是結構體中邊界要求最嚴格的資料型別所要求的位置。因此,成員a(最左邊那個方框)必須儲存於乙個能夠被4整除的位址。結構的下乙個成員是乙個整型值,所以它必須跳過3個位元組到達合適的邊界才能儲存。在整型值之後是最後乙個字元。

如果宣告了相同型別的第二個變數,它的起始儲存位置也必須滿足4這個邊界,所以第乙個結構體的後面還要再跳過3個位元組才能儲存第二個結構體。因此,每個結構體將佔據12個位元組的記憶體空間,但實際只使用了其中的6個,這個利用率可不是很出色。

我們可以在宣告中對結構體的成員列表重新排列,讓那些對邊界要求最嚴格的成員首先出現,對邊界要求最弱的成員最後出現。這種做法可以最大限度地減少因邊界對齊而帶來的空間損失。例如:

struct align2 ;
它所包含的成員和前面那個結構體一樣,但它只占用8個位元組的空間,節省了三分之一。兩個字元可以緊挨著儲存,所以只有結構體最後面需要跳過的兩個位元組被浪費。

有時,我們有充分的理由,決定不對結構體的成員進行重新排列以減少因對齊帶來的空間損失,例如:我們可能想把相關的結構體成員儲存在一起,提高程式的可維護性和可讀性。但是,如果不存在這樣的理由,結構體的成員應該根據它們的邊界需要進行重新排列,減少因邊界對齊而造成的記憶體損失。

當程式將建立幾百個甚至幾千個結構體時,減少記憶體浪費的要求就比程式的可讀性更為急迫。在這種情況下,在宣告中增加注釋可能避免可讀性方面的損失。

sizeof操作符可以得出乙個結構體的整體長度,包括因邊界對齊而跳過的那些位元組。如果你必須確定結構體中某個成員的實際位置,應該考慮邊界對齊因素,可以使用offsetof巨集:

#include 

// 得到指定成員開始儲存的位置距離結構體開始儲存的位置偏移了幾個位元組

size_t offsetof( structname, membername );

例如,拿之前宣告的結構體舉例:

offsetof( struct align, b )的返回值為4。

許多實際的計算機系統對基本型別資料在記憶體中存放的位置有限制,它們會要求這些資料的起始位址的值是某個數k的倍數,這就是所謂的記憶體對齊,而這個k則被稱為該資料型別的對齊模數(alignment modulus)。這種強制的要求一來簡化了處理器與記憶體之間傳輸系統的設計,二來可以提公升讀取資料的速度。

比如這麼一種處理器,它每次讀寫記憶體的時候都從某個8的倍數的位址開始,一次讀出或寫入8個位元組的資料,假如軟體能保證double型別的資料都從8倍數字址開始,那麼讀或寫乙個double型別資料就只需要一次記憶體操作。否則,我們就可能需要兩次記憶體操作才能完成這個動作,因為資料或許恰好橫跨在兩個符合對齊要求的8位元組記憶體塊上。

參考資料:

1.kenneth a. reek.c和指標.北京:人民郵電出版社,2008

2.

結構體內存對齊問題

問題描述 結構體內存對齊問題值直接的體現就是計算結構體的sizeof占用的位元組數。結構體內存對齊的幾個原則,有了這幾個原則,不管結構體裡面是什麼元素,我們都能夠正確算出sizeof值 以vs2013為例 原則2 在原則1的基礎上,檢查計算出的儲存單元是否為所有元素中最寬的元素的長度的整數倍,是,則...

結構體內存對齊問題

今天參加的c c 筆試,總的來說,感覺已經比以前好多了,相信是每天及時總結的緣故,廢話不多說,下面繼續堅持。今天大致做了三塊內容,首先計算機網路通訊,然後是資料結構部分,最後才是c c 的題目。前兩者另外再做小結,先就c c 1 記憶體對齊問題 對這個問題,以前我也總結過,一段時間沒有回看盡然有點忘...

結構體內存對齊問題

假設cpu要讀取乙個4位元組大小的資料到暫存器中 假設記憶體讀取粒度是4 分兩種情況討論 1.資料從0位元組開始 記憶體對齊 2.資料從1位元組開始 記憶體不對齊 當資料從1位元組開始的時候,問題很複雜,首先先將前4個位元組讀到暫存器,並再次讀在這裡插入 片了這麼多額外操作,大大降低了cpu 的效能...