1. 程式人生 > >c++ struct 記憶體對齊

c++ struct 記憶體對齊

結構體的記憶體佈局依賴於cpu,作業系統,編譯器以及編譯時的選項。
考慮三點:
1.成員對齊
每個成員變數存放的位置相對於結構體起始位置的偏移量必須為該變數型別所佔用位元組數的倍數。
空缺的位元組由編譯器自動padding,padding的值根據記憶體分配的不同,也會有所不同,這需要接下來的測試。
2.結構體對齊
結構體型別的對齊要求不能比它內部型別中要求最嚴格的那個寬鬆,也就是要是最大型別的整數倍
3.編譯選項
VC 中提供了#pragma pack(n)來設定變數以n位元組對齊方式。n位元組對齊就是說變數存放的起始地址的偏移量有兩種情況:第一、如果n大於等於該變數所佔用的位元組數,那麼偏 移量必須滿足預設的對齊方式,第二、如果n小於該變數的型別所佔用的位元組數,那麼偏移量為n的倍數,不用滿足預設的對齊方式。結構的總大小也有個約束條 件,分下面兩種情況:如果n大於所有成員變數型別所佔用的位元組數,那麼結構的總大小必須為佔用空間最大的變數佔用的空間數的倍數。

struct MyStruct
{
char dda;
double dda1;  
int type
};

(簡單說明)

struct MyStruct
{
char dda;           //偏移量為0,滿足對齊方式,dda佔用1個位元組;
double dda1;                //下一個可用的地址的偏移量為1,不是sizeof(double)=8的倍數,需要補足7個位元組才能使偏移量變為8(滿足對齊方式),因此VC自動填充7個位元組,dda1存放在偏移量為8的地址上,它佔用8個位元組。
int type;//下一個可用的地址的偏移量為16,是sizeof(int)=4的倍數,滿足int的對齊方式,所以不需要VC自動填充,type存放在偏移量為16的地址上,它佔用4個位元組。
};//所有成員變數都分配了空間,空間總的大小為1+7+8+4=20,不是結構的節邊界數(即結構中佔用最大空間的型別所佔用的位元組數sizeof(double)=8)的倍數,所以需要填充4個位元組,以滿足結構的大小為sizeof(double)=8的倍數。

所以該結構總的大小為:sizeof(MyStruc)為1+7+8+4+4=24。其中總的有7+4=11個位元組是VC自動填充的,沒有放任何有意義的東西。
注意填充的內容可能和記憶體分配方式有關。

記憶體對齊的原因:
cpu讀取記憶體是以2的整數次冪為單位讀取,如果不進行對齊,那麼本來只需要一次進行的訪問,可能需要好幾次才能完成,並且還要進行額外的merger或者資料分離。

一個例子:

#include <stdio.h>

int main(int argc, const char * argv[])
{
    int a=1;
    long b=2;
    int c=3;

    int *p=&a;
    int *q=p;

    printf("%16p%16p%16p\n%16p%16p\n",&a,&b,&c,&p,&q);

    return 0;
}

一個變數的地址打印出來是格式化字串可能有12個位元組大小,如果看一個指標的·大小,用sizeof(&a)的方法。