sizeof系列——struct class union

struct:


struct MyStruct

{   

   double a;

   char   b;

   int    c;

};


sizeof(MyStrut)=?????

很多朋友會認爲結果是:8(sizeof(a))+1(sizeof(b))+4(sizeof(c))=13


但是當我們在vs上運行輸出的結果是 16,這是爲什麼呢?


這是編譯器爲了提高cup的存儲速度對一些起始地址進行了"對齊"處理.


雖然對齊原則和編譯器有關聯但是以下的原則是必須遵守的:


  1. 結構體變量的首地址能夠被其最寬基本類型成員的大小整除。

  2. 結構體每個成員相對於結構體首地址偏移量都是成員大小的整數倍,不夠就進行字節填充。

  3. 結構體的總大小爲最寬數據成員的整數倍,不夠就字節填充。


所以再將目光轉向MyStruct:

第一個變量a首地址偏移量爲0,是sizeof(a)=8的整數倍,所以佔用8+0=8個字節。

第二個變量b首地址偏移量爲8,是sizeof(b)=1的整數倍,所以佔用1個字節,將b放在偏移量爲8的地方。

第三個變量c首地址偏移量8+1=9,不是sizeof(c)=4的整數倍所以進行字節填充9+3=12(離9最近的4的倍數),變量c佔用4個字節。

綜上:8+1+3+4=16 16是最大數據類型double=8的整數倍(不用補充字節),所以最後結果是16.


如果我們將MyStruct的數據位置換一下

struct MyStruct

{   

   char a;

   double   b;

   int    c;

};

那麼sizeof(MyStruct)的結果會是

sizeof(a)=1;

sizeof(b)=8;

sizeof(c)=4;

(1+7+8+4)=20;(包含了填充字節);

但是20不是8的整數倍所以填充字節20+4=24(離20最近的8的整數倍)


當然我們也可以用#pragam pack(n)來終結這種喪心病狂的對齊方式

eg:

#pragam pack(push)//保存對齊狀態

#pragam pack(4)(以4字節方式對齊)


struct Test

   char a;

   double b;

   int   c;

};


#pragam pack(pop)


原則:


若n>變量字節 採用默認對齊方式

若n<變量字節 採用n的倍數對齊方式

若n>所有變量(單個)的字節數,那麼總大小爲最大變量的整數倍,否則爲n的整數倍


sizeof(Test)=1+3+8+4=13 補齊3個字節=16;


若把#pragam pack(4)改爲#pragam pack(16)

sizeof(Test)=1+7+8+4+4=24;


union:


union Test

{

   int a;

   double b;

   char c;

};


sizeof(Test)

sizeof(a)=4;

sizeof(b)=8;

sizeof(c)=1;


sizeof(Test)以最長爲所有字節 8 又因爲8是8的倍數所以最後爲8(union以單個最長字節對齊


class:

一、個空類

class A

};

    求sizeof的結果是1,因爲即使是沒有成員之類的,一個類存在,至少都要給他一個空間,不然就沒有存在的意義了。

二、簡單的類

class A

{

    int a;

    virtual fun();

}

    這個也好求,就是sizeof(A.a)+4(指向虛表的指針)

三、子類普通繼承、父類中不含虛函數

class  A

{

    int a;

}

class B:public A

{

     int b;

     virtual fun();

}

sizeof(B)=sizeof(A)+sizeof(B.b)+4(指向虛表指針)

四、子類普通繼承、父類含虛函數

class  A

{

    int a;

    virtual fun1();

}

class B:public A

{

     int b;

     virtual fun();

}

sizeof(B)=sizeof(A)-4(sizeof(A)中有一個指向虛表的指針)+sizeof(B.b)+4(指向虛表指針)

因爲普通繼承,子類和父類的虛函數存放在同一個虛表中,所以,只需要存一個指向續表的指針即可;

五、子類虛繼承、父類不含虛函數

class  A

{

    int a;

   

}

class B:virtual public A

{

     int b;

     virtual fun();

}

sizeof(B)=sizeof(A)+4(指示父類存放空間的起始偏移量)+sizeof(B.b)+4(指向B的虛表的指針)

六、子類虛繼承、父類含虛函數

class  A

{

    int a;

    virtual fun1();

   

}

class B:virtual public A

{

     int b;

     virtual fun();

}

sizeof(B)=sizeof(A)+4(指示父類存放空間的起始偏移量)+sizeof(B.b)+4(指向B的虛表的指針)

虛繼承時,父類和子類的虛函數表分開放,所以,分別存儲兩個指向對應續表的指針,因而不用減去sizeof(A)中續表指針的大小。




  



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章