深度解析結構體類型地址偏移量相關問題


Q1:什么是偏移量?

A:結構體變量中成員的地址和結構體變量地址之差。可以用offsetof(type, member)宏來確定成員的實際位置(定義於stddef.h),其中type是結構體類型,member是成員名。可知:第一個成員的偏移量為0,最后一個成員的偏移量加上最后一個成員的大小卻不一定等於結構體大小(先賣個關子=。。=)。

Q2:什么是地址對齊?

A:結構體成員是按照聲明的順序存儲在連續的內存空間中,而結構體成員的類型不一定相同,系統在存儲結構體時不是像數組一樣將各個成員大小簡單相加,而需要考慮地址對齊問題。

先來簡單看一個例子:

  

Q3:上述兩種形式的結構體大小是否相同?

A:不相等,雖然結構體成員相同,但是由於聲明順序不同導致地址偏移量不同。具體而言第一個結構體大小為16,第二個為24。

   

 

Q4:結構體存儲時地址對齊,編譯器需要遵循什么原則?

A:兩條原則:

1.結構體變量中成員的偏移量必須是成員大小的整數倍;

2.結構體大小必須是所有成員大小的整數倍,即所有成員大小的公倍數。

對照上述兩條原則,回過來看上述兩個結構體大小是不是清楚明白了?Student1很好理解,Student2中scores成員偏移量為16,加上自身大小4后為20,由於20不是8的整數倍,去最小公倍數24為整個結構體大小。(最后一個成員的偏移量加上最后一個成員的大小卻不一定等於結構體大小=。。=)

 

-------------------------------------------我是一條可愛的分割線-------------------------------------------------------

增加點難度,再來看一個例子:

  

大家思考一下結構體Student3的大小?結構體ss偏移量?結構體ss大小為8,如果將ss當作一個整體Student3大小是不是24?

測試結果卻是:

Q5:出現結構體嵌套時,怎么計算結構體大小?

A:上述兩個原則需要修改一下:

1.展開后的結構體的第一個成員的偏移量(嵌套的結構體偏移量)應當是被展開的結構體中最大成員的整數倍;

2.結構體大小必須是所有成員大小的整數倍,這里計算的是展開后的成員,而不是將嵌套的結構體看作一個整體。

 

總結與反思:了解結構體存儲方式后,我們該怎么做才能充分利用內存,減少邊界對齊帶來的空間損失?

1.重排結構體成員聲明列表,讓那些對邊界要求最嚴格(大)的成員首先出現,對邊界要求最弱(小)的成員最后出現;

2.在考慮程序的可讀性和可維護性的前提下,可以把相關聯的成員放在一起而不用考慮列表順序問題,否則參考1;

3.在程序聲明幾百個甚至幾千個結構體時,減少內存的浪費要比程序的可讀性更為急迫,這時可以通過增加注釋來提高可讀性。

 

tip:如何給結構體變量分配空間由編譯器決定,以上代碼均在linux/GCC下編譯,windows/VC也是如此,其他平台可能有不同的處理方式。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM