1. 程式人生 > >c++struct sizeof大小對齊方式

c++struct sizeof大小對齊方式

先讓我們看四個重要的基本概念:1.資料型別自身的對齊值:對於char型資料,其自身對齊值為1,對於short型為2,對於int,float,double型別,其自身對齊值為4,單位位元組。2.結構體或者類的自身對齊值:其成員中自身對齊值最大的那個值。3.指定對齊值#pragma pack (value)時的指定對齊值value4.資料成員、結構體和類的有效對齊值:自身對齊值和指定對齊值中小的那個值。了這些值,我們就可以很方便的來討論具體資料結構的成員和其自身的對齊方式。有效對齊值N是最終用來決定資料存放地址方式的值,最重要。有效對齊N,就是表示對齊在N,也就是說該資料的"存放起始地址
%N=0"
.而資料結構中的資料變數都是按定義的先後順序來排放的。第一個資料變數的起始地址就是數據結構的起始地址。結構體的成員變數要對齊排放,結構體本身也要根據自身的有效對齊值圓整(就是結構體成員變數佔用總長度需要是對結構體有效對齊值的整數倍,結合下面例子理解)。這樣就不能理解上面的幾個例子的值了。例子分析:分析例子B
struct B
{
    char b;
    int a;
    short c;
};
B從地址空間0x0000開始排放。該例子中沒有定義指定對齊值,在筆者環境下,該值預設為4。第一個成員變數b的自身對齊值是1,比指定或者預設指定對齊值4小,所以其有效對齊值為1,所以其存放地址
0x0000符合0x0000%1=0.第二個成員變數a,其自身對齊值為4,所以有效對齊值也為4所以只能存放在起始地址為0x00040x0007這四個連續的位元組空間中,複核0x0004%4=0,且緊靠第一個變數。第三個變數c,自身對齊值為 2,所以有效對齊值也是2,可以存放在0x00080x0009這兩個位元組空間中,符合0x0008%2=0。所以從0x00000x0009存放的都是B內容。再看資料結構B的自身對齊值為其變數中最大對齊值(這裡是b)所以就是4,所以結構體的有效對齊值也是4。根據結構體圓整的要求, 0x00090x0000=10位元組,(102)%40。所以0x0000A0x000B也為結構體B所佔用。故B0x00000x000B共有12個位元組,sizeof(struct B)=12;其實如果就這一個就來說它已將滿足位元組對齊了
,因為它的起始地址是0,因此肯定是對齊的,之所以在後面補充2個位元組,是因為編譯器為了實現結構陣列的存取效率,試想如果我們定義了一個結構B的陣列,麼第一個結構起始地址是0沒有問題,但是第二個結構呢?按照陣列的定義,陣列中所有元素都是緊挨著的,如果我們不把結構的大小補充為4的整數倍,那麼下一個結構的起始地址將是0x0000A,這顯然不能滿足結構的地址對齊了,因此我們要把結構補充成有效對齊大小的整數倍.其實諸如:對於char型資料,其自身對齊值為1,對於short型為2,對於int,float型別,其自身對齊值為4,double自身對齊值為8,這些已有型別的自身對齊值也是基於陣列考慮的,是因為這些型別的長度已知了,所以他們的自身對齊值也就已知了.
同理,分析上面例子C
#pragma pack (2) /*
指定按2位元組對齊*/
struct C
{
    char b;
    int a;
    short c;
};
#pragma pack () /*
取消指定對齊,恢復預設對齊*/
一個變數b的自身對齊值為1,指定對齊值為2,所以,其有效對齊值為1,假設C0x0000開始,那麼b存放在0x0000,符合0x0000%1= 0;第二個變數,自身對齊值為4,指定對齊值為2,所以有效對齊值為2,所以順序存放在0x00020x00030x00040x0005四個連續位元組中,符合0x0002%2=0。第三個變數c的自身對齊值為2,所以有效對齊值為2,順序存放0x00060x0007中,符合 0x0006%2=0。所以從0x00000x00007共八位元組存放的是C的變數。又C的自身對齊值為4,所以C的有效對齊值為2。又8%2=0,C只佔用0x00000x0007的八個位元組。所以sizeof(structC)=8.