結構體(或者聯合體)變量的成員在內存里是如何分布的


1.概述

結構體變量的成員在內存里是如何分布的、成員先后順序是怎樣的、成員之間是連續的還是分散的、還是其他的什么形式?這些問題既和軟件相關又和硬件相關。所謂軟件相關主要是指和具體的編程語言的編譯器的特性相關,編譯器為了優化CPU訪問內存的效率,在生成結構體成員的起始地址時遵循着某種特定的規則,這就是所謂的 結構體成員“對齊”;所謂硬件相關主要是指CPU的“字節序”問題,也就是大於一個字節類型的數據如int類型、short類型等,在內存中的存放順序,即單個字節與高低地址的對應關系。

2.分布規則

(1)為了提高CPU訪問內存的效率,程序語言的編譯器在做變量的存儲分配時進行了優化處理,處理的原則是:對於n字節的元素,它的首地址能被n整除,這種原則稱為“對齊”。

(2)結構體(聯合體)的成員所占內存地址依次增高,第一個成員位於低地址處,最后一個成員位於高地址處,但是結構體成員的內存並不是連續的,編譯器會對成員做上述“對齊”處理。

(3)通常編譯器可以設置一個對齊參數n,結構體中每個成員實際對齊參數N根據N=min(sizeof(成員類型),n)來得到。結構體成員的內存偏移地址x,滿足條件x%N=0。

(4)結構體所有成員的對齊參數N的最大值稱為結構體的對齊參數。整個結構的長度必須是結構體對齊參數的最小整數倍,不夠補0。

簡單來說:

1)結構體的起始地址為x,x%sizeof(結構體)=0。

2)結構體每個成員相對於起始地址偏移地址y,y%N=0。

3)結構體長度等於結構體對齊參數的最小整數倍。

注:編譯器對齊參數可以通過指令控制,例如#param pack(2)兩字節對齊。vs2010IDE還可以通過"項目屬性"->"C/C++"->"代碼生成"->“結構成員對齊”來設置。編譯器默認對齊參數為8個字節。

例:

struct A
{
    char      c;   //1byte
    double    d;   //8byte
    short     s;   //2byte
    int       i;   //4byte
};
int main(int argc, char*argv[])
{
    A strua;
    printf("len:%d\n",sizeof(A));
    printf("%d,%d,%d,%d",&strua.c,&strua.d,&strua.s,&strua.i);
    return 0;
}

輸出結果為:
len:24
1506156,1506164,1506172,1506176

3.特殊成員

(1)結構體成員為數組時,是將數組的每個元素當一個成員來分配,並不是將整個數組當成一個成員來對待。其他成員的分配規則按照上述規則。

(2)當結構體成員是位段時,存儲是按其類型分配空間的,如int型的位段就分配4個字節的存儲單元。相鄰的同類型的兩個位段,如果該類型的長度夠用,就將兩位段連續存放,共用存儲單元,如果不夠用,就另起一個該類型長度的存儲空間。相鄰的不同類型的兩個位段,分別為這兩個位段分配它們所屬類型長度的存儲空間。其他成員的分配規則按照上述規則。

1)例1:

struct bit  
{  
    int a:3;
    int b:2;
    int c:3;
};
int main(int argc,char* argv[])    
{    
    bit s;    
    char *c = (char*)&s;    
    *c = 0x99;    
    cout<<s.a<<endl<<s.b<<endl<<s.c<<endl;  
    return 0;    
}

輸出結果:  1   -1   -4  

分析:

hex    0x99

bin    100  11   001

            c      b       a

地址   高   -->     低

cpu為小端模式,高位比特存儲在高地址中,低位比特存儲在低地址中。而且計算機中存儲的是數的補碼形式。

2)例2:

struct   bit  
{  
    char   a:5;
    char   b:4;
    char   c:7;
};
int main(int argc,char* argv[])    
{    
    bit s;    
    int *c = (int*)&s;    
    *c = 0x99E00000;    
    cout<<sizeof(bit)<<endl<<(int)s.a<<endl<<(int)s.b<<endl<<(int)s.c<<endl;  
    return   0;    
}

輸出結果:3 0 0 -32

hex    0x99          0xE0         0x00           0x00

bin   10011001  11100000  00000000  00000000

 

                                  c                   b                a

 

地址      高                    -->                       低

 


免責聲明!

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



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