對齊的作用和原因:各個硬體平台對儲存空間的處理上有很大的不同。一些平台對某些特定型別的資料只能從某些特定位址開始訪問。其他平台可能沒有這種情況,但是最常見的是如果不按照適合其平台要求對資料存放進行對齊,會在訪問效率上帶來損失。
語法:#pragma pack( [show] | [push | pop] [, identifier], n )
在不指定對齊方式時 編譯器預設大小為8
可以通過命令 #pragma pack (show) 檢視
那就從預設的開始說起,由於預設是8 ,結構體如下
typedef struct test_s
{char b;
int a;
short c;
sizeof(test_s) = ? 應該是12,為何?
原因:假設test_s從位址空間0x0000開始存放。沒有定義指定對齊值,該值預設為8。
第乙個成員變數b的自身對齊值是1,比指定或者預設指定對齊值8小,所以其有效對齊值為1,所以其存放位址0x0000符合0x0000%1=0.
第二個成員變數a,其自身對齊值為4,比指定或者預設指定對齊值8小,所以其有效對齊值為4,所以只能存放在起始位址為0x0004到0x0007這四個連續的位元組空間中,符合0x0004%4=0, 且緊靠第乙個變數。
第三個變數c,自身對齊值為2,比指定或者預設指定對齊值8小,所以其有效對齊值為2,可以存放在0x0008到0x0009這兩個位元組空間中,符合0x0008%2=0。所以從0x0000到0x0009存放的都是b內容。
再看資料結構b的自身對齊值為其變數中最大對齊值(這裡是b)所以就是4,所以結構體的有效對齊值也是4。根據結構體圓整的要求,0x0009到0x0000=10位元組,(10+2)%4=0。所以0x0000a到0x000b也為結構體b所占用。故b從0x0000到0x000b共有12個位元組,sizeof(struct b)=12;
***************===分割線******************************==
重新指定對齊大小
#pragma pack(push)
#pragma pack(2)
typedef struct test_s
{char b;
int a;
short c;
#pragma pack(pop)
sizeof(test_s) = ? 應該是8,為何?
原因:假設test_s從位址空間0x0000開始存放。指定對齊值為2。
第乙個成員變數b的自身對齊值是1,比指定或者預設指定對齊值2小,所以其有效對齊值為1,所以其存放位址0x0000符合0x0000%1=0.
第二個成員變數a,其自身對齊值為4,比指定或者預設指定對齊值2大,所以其有效對齊值為2,所以只能存放在起始位址為0x0002到0x0005這四個連續的位元組空間中,符合0x0002%2=0, 且緊靠第乙個變數。
第三個變數c,自身對齊值為2,與指定或者預設指定對齊值2一樣,所以其有效對齊值為2,可以存放在0x0006到0x0008這兩個位元組空間中,符合0x0006%2=0。所以從0x0000到0x0008存放的都是b內容。
再看資料結構b的自身對齊值為其變數中最大對齊值(這裡是b)所以就是4,但結構體的有效對齊值是2。根據結構體圓整的要求,0x0008到0x0000=8位元組,(8)%2=0。所以b從0x0000到0x0008共有8個位元組,sizeof(struct b)=8;
***************===分割線******************************==
重新指定對齊大小
#pragma pack(push)
#pragma pack(1)
typedef struct test_s
{char b;
int a;
short c;
#pragma pack(pop)
sizeof(test_s) = ? 應該是7,為何?
原因:假設test_s從位址空間0x0000開始存放。指定對齊值為1。
第乙個成員變數b的自身對齊值是1,與指定或者預設指定對齊值1一樣,所以其有效對齊值為1,所以其存放位址0x0000符合0x0000%1=0.
第二個成員變數a,其自身對齊值為4,比指定或者預設指定對齊值1大,所以其有效對齊值為1,所以只能存放在起始位址為0x0001到0x0004這四個連續的位元組空間中,符合0x0001%1=0, 且緊靠第乙個變數。
第三個變數c,自身對齊值為2,比指定或者預設指定對齊值1大,所以其有效對齊值為1,可以存放在0x0005到0x0007這兩個位元組空間中,符合0x0005%1=0。所以從0x0000到0x0007存放的都是b內容。
再看資料結構b的自身對齊值為其變數中最大對齊值(這裡是b)所以就是4,但結構體的有效對齊值是1。根據結構體圓整的要求,0x0007到0x0000=7位元組,(7)%1=0。所以b從0x0000到0x0007共有7個位元組,sizeof(struct b)=7;
********************===分割線***************===
現在思路是否清晰一些呢,現在如果在增加乙個結構體成員 在看看什麼效果
#pragma pack(push)
#pragma pack(2)
typedef struct test_s
{char b;
char e;
int a;
short c;
#pragma pack(pop)
sizeof(test_s) = ? 應該是8,為何?
增加了乙個成員 在長度沒變。如果指定對齊大小為4呢 ?sizeof(test_s) = ? 應該是12
根據上面的理論應該都可以推算出來的~
總結一下:
1:如果沒指定對齊大小 ,那就按照預設大小對齊,預設值大小為多少可以通過命令檢視,前面已經提到了。
2:如果指定了對齊大小,那就要看結構體裡的成員大小與指定大小比較,按照值較小的對齊。
3:計算大小的同時 要注意結構體的取整要求。
結構體對齊方式詳解
1 平台原因 移植原因 不是所有的硬體平台都能訪問任意位址上的任意資料的 某些硬體平台只能在某些位址處取某些特定型別的資料,否則丟擲硬體異常。2 效能原因 資料結構 尤其是棧 應該盡可能地在自然邊界上對齊。原因在於,為了訪問未對齊的記憶體,處理器需要作兩次記憶體訪問 而對齊的記憶體訪問僅需要一次訪問...
結構體對齊計算方式
結構體的大小也不是成員型別大小的簡單相加。需要考慮到系統在儲存結構體變數時的位址對齊問題。由於儲存變數位址對齊的問題,結構體大小計算必須滿足兩條原則 一 結構體成員的偏移量必須是成員大小的整數倍 0被認為是任何數的整數倍 二 結構體大小必須是所有成員大小的整數倍 陣列除外,結構體中的結構體按單個變數...
有關結構體位元組對齊方式
今天偶然碰到對如下兩個結構體進行sizeof 運算 struct example1 struct example2 在計算機上執行後得到分別為24,16,網上查了一下,得到如下理解 1.計算方式 sizeof struct offsetof last item sizeof last item si...