內存對齊原則:
1、結構體變量的首地址可以被其最寬基本類型成員大小與對齊基數中的較小者所整除;
2、結構體每一個成員相對於結構體首地址的偏移量(offset)都是該成員大小與對齊基數中的較小者的整數倍,若有須要編譯器會在成員之間加上填充字節(internal adding);
3、結構體的總大小爲結構體最寬基本類型成員大小與對齊基數中的較小者的整數倍,若有須要編譯器會在最末一個成員以後加上填充字節(trailing padding)。ios
關於結構體分配內存和字節對齊原則
今天看到一個關於sizeof的使用問題,而且提到了計算機組成原理中的字節對齊,寫了以下測試程序,發現了一些問題:ide
#include <iostream>
#include <malloc.h>
#include <stdlib.h>
using namespace std;測試
struct S0 {};spa
struct S1
{
char a;
int b;
};ip
struct S2
{
int x;
char y;
};內存
struct S3
{
char c1;
S1 s;
char c2;
};開發
int main ()
{編譯器
cout << "Testing S0 ...\n";
cout << sizeof(S0);
cout << "\n\n";
cout << "Testing S1 ...\n";
cout << sizeof(S1) << endl;
S1 s1 = {'a', 0x22222222};
cout << sizeof(s1) << endl;
cout << &s1 << endl;
char *p1 = (char*)malloc(sizeof(char)*sizeof(s1));
memcpy (p1, &s1, sizeof(s1));
for (int i=0; i<sizeof(s1); i++)
printf ("%x ",*(p1+i));
cout << "\n\n";it
cout << "Testing S2 ...\n";
cout << sizeof(S2) << endl;
S2 s2 = {0x22222222, 'a'};
cout << sizeof(s2) << endl;
cout << &s2 << endl;
char *p2 = (char*)malloc(sizeof(char)*sizeof(s2));
memcpy (p2, &s1, sizeof(s2));
for (int i=0; i<sizeof(s2); i++)
printf ("%x ",*(p2+i));
cout << "\n\n";io
cout << "Testing S3 ...\n";
cout << sizeof(S3) << endl;
S3 s3 = {'b', s1, 'c'};
cout << sizeof(s3) << endl;
cout << &s3 << endl;
char *p3 = (char*)malloc(sizeof(char)*sizeof(s3));
memcpy (p3, &s3, sizeof(s3));
for (int i=0; i<sizeof(s3); i++)
printf ("%x ",*(p3+i));
cout << "\n\n";
return 0;
}
/*-------------------------------------------------------------------------------------------
Eclipse+CDT下運行結果:
Testing S0 ...
1
Testing S1 ...
8
8
0x22ff80
61 0 40 0 22 22 22 22
Testing S2 ...
8
8
0x22ff70
61 0 40 0 22 22 22 22
Testing S3 ...
16
16
0x22ff58
62 ffffffff 22 0 61 0 40 0 22 22 22 22 63 10 40 0
--------------------------------------------------------------------------------------------*/
總結規律發現:
在結構體中每一個像出現char這樣佔一個字節的變量後面會自動補上3個字節,使之變爲和int同樣大小的4字節變量。 因此S1和S2就是佔了8字節的內存,S3佔了16字節的內存。
關於字節對齊:
查閱資料後發現,字節對齊有助於加快計算機的取數速度,不然就得多花指令週期了。爲此,編譯器默認會對結構體進行處理(實際上其它地方的數據變量也是如此),讓寬度爲2的基本數據類型(short等)都位於能被2整除的地址上,讓寬度爲4的基本數據類型(int等)都位於能被4整除的地址上,以此類推。這樣,兩個數中間就可能須要加入填充字節,因此整個結構體的sizeof值就增加了。
字節對齊的細節和編譯器實現相關,但通常而言,知足三個準則: 1) 結構體變量的首地址可以被其最寬基本類型成員的大小所整除; 2) 結構體每一個成員相對於結構體首地址的偏移量(offset)都是成員大小的整數倍,若有須要編譯器會在成員之間加上填充字節(internal adding); 3) 結構體的總大小爲結構體最寬基本類型成員大小的整數倍,若有須要編譯器會在最末一個成員以後加上填充字節(trailing padding)。 例如對S3來看: S3中的S1實際上是打散的int和char,因此至關是char,int,char,char,最長的寬度是int爲4字節,因此要保證char也是佔據4字節,因此最終就是總共16字節所示結果。 62 ffffffff 22 0 61 0 40 0 22 22 22 22 63 10 40 0。 恩,搞移動開發對每一byte的內存都很珍惜啊~~~~~嚴重鄙視像Vista這樣沒幹什麼事就耗我七百多兆內存的系統。。