關於C語言中結構體中的結構體成員導致的字節對齊問題


關於結構體的字節對齊是什么,就不贅述,再此附上一篇文章,介紹字節對齊:http://www.linuxsong.org/2010/09/c-byte-alignment/

這里的結構體字節對齊的數據類型都是基本數據類型,如果結構體的定義中含有結構體成員呢?

網上有很多人寫博客談到這個問題,都認為該結構體成員應該被看做一個整體,按照整體的字節數來進行字節對齊,選擇首地址。但是經過測試,這種說法是不對的。

 1 struct s1{
 2    char c1;
 3    char c2;
 4    char c3;
 5    char c4; 
 6 };
 7 
 8 struct s2{
 9     char a;
10     struct s1 s;
11 };

對於上述代碼,顯然sizeof(struct s1) = 4。如果將struct s1看做整體,來進行字節對齊的話,sizeof(struct s2)應該是等於8。但是該段代碼在gcc和VS2010下測試的結果都是5。

所以,s2的內存布局如下

s2 : char | char char char char |

s的首地址並非為4,而是char類型長度的整數倍

同樣,對於結構體:

 1 struct S1
 2 {
 3     char a;
 4     short b;
 5 };
 6 
 7 struct S2
 8 {
 9     char a;
10     struct S1 s;
11 };

上述代碼中,sizeof(struct S1) = 4,而sizeof(struct S2) = 6。

S2的內存布局是:

S2 : char **** | char **** short short

s的首地址並非為4,而是short類型長度的整數倍,結構體S2的長度並非結構體S1長度的整數倍,而是short類型長度的整數倍

相對的,我們可以看一下結構體:

struct S
{
    char a;
    char b;
    short c;
};

sizeof(S) = 4。

其內存布局為:

S : char char short short

對比S2和S,我們看到,S2中的s結構體成員確實是仍按它作為S1結構體的整體(占用4個字節)來布局的。

 

那么我們可以得出這情形下的字節對齊問題的結論:

1)結構體中的結構體成員,是按照原結構體的內存布局在新結構體中進行布局的;

2)結構體中的結構體成員,其內存首地址為該成員中最長數據類型的整數倍;

3)結構體的整體長度與其中的結構體成員無關,而是整個結構體(包括結構體成員內部)中的最長數據類型的整數倍。

 

得出結論后,我們回到處理器本身,來探討一下編譯器之所以這么處理的原因。

從CPU結構角度看內存對齊有一篇比較易懂的文章:

http://hi.baidu.com/maikeai/item/4976f24cc0f905d3c1a592a0

從該文章中,我們可以知道,之所以需要內存對齊,是CPU為了讀取數據時減少讀取存儲器的次數,提高效率。

對於32位的CPU,一次最多讀入雙字的32位數據,而對於超過32位的數據,在32位的計算機上,就必須多次讀取存儲器,這與是否字節對齊無關。

我們可以看到,字節對齊,其實實質上是在拿存儲器的空間,換CPU的時間。

所以,對於C語言內置的數據類型,可以很好地通過內存對齊來節省時間,同時其浪費的存儲器空間也是可控的。

但是,對於結構體成員來說,因為它的長度是不可控的,所以如果強行按整體內存對齊,首先可能因為長度過長,即使內存對齊需要的存儲器讀取次數也很多,導致優化的時間不明顯,另外,也可能導致浪費的存儲器空間太大。所以,最簡單的平衡空間和時間的方法,就是按照該結構體成員中最長數據類型來進行字節對齊,這樣最有可能減少存儲器讀取次數,也使浪費的存儲器空間可控。

 

 


免責聲明!

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



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