看這樣乙個筆試題:
#include
using
namespace
std;
#pragma pack(8)
struct example1
;struct example2
;#pragma pack()
int main(int argc, char* argv)
問程式的輸出結果是什麼?
答案是 8,16,4
struct是一種復合資料型別,其構成元素既可以是基本資料型別的變數,也可以是復合資料型別(如struct、union等)。對於struct,編譯器會自動進行成員變數的對齊,以提高運算效率。預設情況下,編譯器為struct的每個成員按其自然對界(natural alignment)條件分配空間。各個成員按照它們被宣告的順序在記憶體中順序儲存,第乙個成員的位址和整個結構的位址相同。
自然對界指按struct的成員中size最大的成員對齊,例如:
struct natural_align
; 在上述struct中,size最大的是short,其長度為2位元組,因而struct中的char成員a、c都以2為單位對齊,sizeof(natural_align)的結果等於6。如果改為:
struct natural_align
; 其結果則變為12。
我們也可以遮蔽掉預設的對齊長度,編譯器提供了」#pragma pack」來讓使用者自定義對齊長度。
語法:#pragma pack([push|pop][, identifier][, n])
呼叫pack時不指定引數,n將被設成預設值;
push:可選引數,將當前指定的packing alignment進行壓棧操作(這裡的棧是編譯器的棧),同時設定當前的packing alignment為n;如果n沒有指定,則只將當前的packing alignment壓棧。
pop:可選引數,從棧中刪除最頂端的記錄;如果沒有指定n,則當前棧頂記錄即為新的packing alignment;如果指定了n,則n將成為新的packing aligment。
n:可選引數,指定packing alignment的數值,以位元組為單位,預設數值是8,合法的數值是1、2、4、8、16。
identifier:可選引數,當同push一起使用時,賦予當前被壓入棧中的記錄乙個名稱;當同pop一起使用時,pop出所有的記錄直到identifier被pop出,如果identifier沒有被找到,則忽略pop操作。
#pragma pack(n)
將按照n個位元組對齊
#pragma pack()
恢復預設對齊長度
#pragma pack(push,n)
把原來對齊長度壓棧,並設新的為n
#pragma pack(pop)
恢復棧頂的對齊長度
總結整理猜測 by liuyuan185442111
struct s1
; struct s2
; sizeof(s1)是8,s1的對齊引數是最大的成員也就是b的大小,為4。
c佔1位元組;d按4位元組對齊;e佔8位元組,e按8位元組對齊,所以記憶體布局就是這樣:
c--
-a--
-bbbb--
--eeeeeeee
檢驗如下:
struct s2 t;
printf("%d",sizeof(struct s2));
printf(",%d",(unsigned
int)&t.d-(unsigned
int)&t.c);
printf(",%d",(unsigned
int)&t.d.b-(unsigned
int)&t.d);
printf(",%d\n",(unsigned
int)&t.e-(unsigned
int)&t.d.b);
//輸出是24,4,4,8.
在例一開頭加上#pragma pack(4)
,輸出結果為20,4,4,4
記憶體布局為:
c---
a---
bbbb
eeee
eeee
c++的類又有點不一樣,因為類中可能有虛指標,指向虛基類的指標。以下測試和結論基於window和vc。
class a
;class b:a
;b b;
b的記憶體結構是ma,mb依次排列。也就是說,普通繼承關係,派生類物件的記憶體布局是先基類的成員,後派生類自己的成員。具體規則和struct中有struct成員的規則相同。
帶有虛函式的類,會有乙個指向虛函式表的指標,這個指標會放在所有資料成員的前邊,也就是說這個指標在物件記憶體區塊的起始位置。
class a
virtual ~a() {}
};class b:a
};b b;
b的記憶體布局是:
00 31 42 00 // 指向虛函式表的指標
b: 1c 00 47 00 // 指標
02 00 00 00
01 00 00 00
c: 28 00 47 00 // 指標
03 00 00 00
01 00 00 00
d: 40 00 47 00 02 00 00 00
34 00 47 00 03 00 00 00
04 00 00 00 01 00 00 00
b和c起始位址有乙個指標,指向乙個關於偏移量的陣列,用來實現虛繼承,關於這個指標,有些複雜,就不說了。
還有一點,b,c,d中,class a中的資料都被放到了末尾。
classa;
class
b:virtual
publica;
//sizeof(a):8,sizeof(b):16
class a
};class b:public a
;//sizeof(a):16,sizeof(b):24
static成員儲存在靜態區,不占用類的大小。
這樣對類取sizeof和物件的sizeof就相同了。
比如:
class
test
;int test::i = 1;
static int i;
相當於宣告;int test::i = 1;
才是定義。
i相當於乙個全域性變數,不過作用域限於test。
c++類的大小——sizeof()
C 結構體大小問題
using system using system.collections.generic using system.linq using system.runtime.interopservices using system.text using system.threading.tasks na...
結構體大小和類大小的計算
舉例 struct a 該結構體中最大的型別是double,所以對齊符為8 1 首先分配8個位元組 2 int a 10 佔40個位元組 3 所以每兩個陣列元素申請8個位元組 4 直到申請5次 40個位元組 才將int a 10 全部分配完畢 5 再為b分配8個位元組 此時已經48個位元組了 6 最...
關於類的大小問題
一直以來在各個論壇上都不時的見過一些關於類大小的討論,尤其是當涉及到虛繼承時,類的大小就變得更加撲朔迷離,每看完乙個帖子都覺得自己有所收穫,但當下次遇到類似的帖子時卻怎麼也想不起自己以前對此問題的記憶了,於是乎,乾脆勤快些一勞永逸地把他們記錄下來。純屬個人理解,難免有錯,我會定期更新這篇文章,修改其...