介紹三個概念:自身對齊值、指定對齊值、有效對齊值。
自身對齊值:數據類型本身的對齊值,例如char類型的自身對齊值是1,short類型是2;
指定對齊值:編譯器或程序員指定的對齊值,32位單片機的指定對齊值默認是4;
有效對齊值:自身對齊值和指定對齊值中較小的那個。
對齊有兩個規則:
1 基本類型變量起始地址要按一定規則對齊.
char 類型,其起始地址要1字節邊界上,即其地址能被1整除(即任意地址即可)
short類型,其起始地址要2字節邊界上,即其地址能被2整除(0x0002,0x0004,0x0006.....,地址的末位能被2整除)
int 類型,其起始地址要4字節邊界上,即其地址能被4整除(0x0004,0x0008,0x00012,0x0016......,地址的末位能被4整除)
long類型,其起始地址要4字節邊界上,即其地址能被4整除(0x0002,0x0004,0x0006......,地址的末位能被4整除)
float類型,其起始地址要4字節邊界上,即其地址能被4整除(0x0002,0x0004,0x0006......,地址的末位能被4整除)
double類型,其起始地址要8字節邊界上,即其地址能被8整除 (0x0008,0x0016,0x0024......,地址的末位能被8整除)
2 結構體地址對齊需要兼顧下面三個方面
1 若結構體中最大佔用空間的成員爲int類型,則整個結構體的起始地址應以4字節爲邊界;2 且結構內成員的偏移量也要參照1中的int類型,滿足相應倍數進行對齊;3 且結構總尺寸也要對齊. 要爲最大尺寸的成員int類型的整數倍,,如果不是則要在結構最後補齊成整數倍例
舉例:
struct A{
char a;
char b;
char c;
char d;
};
0x0000 |
0x00001 |
0x0002 |
0x0003 |
a |
b |
c |
d |
結構體A佔4個字節, (0x0000~0x003總內存大小爲4,爲char類型大小的倍數)
假如結構體A起始地址是0x0000,
成員a的自身對齊值1,指定對齊值4,所以有效對齊值是1,地址0x0000是1的整數倍,故a存放起始地址是0x0000,佔一個字節;
成員b的自身對齊值1,指定對齊值4,所以有效對齊值是1,地址0x0001是1的整數倍,故b存放起始地址是0x0001,佔一個字節;
成員c的自身對齊值1,指定對齊值4,所以有效對齊值是1,地址0x0002是1的整數倍,故c存放起始地址是0x0002,佔一個字節;
成員d的自身對齊值1,指定對齊值4,所以有效對齊值是1,地址0x0003是1的整數倍,故d存放起始地址是0x0003,佔一個字節;
此時結構體A的有效對齊值是其最大數據成員的自身對齊值,它的成員都是char類型,故結構體A的有效對齊值是1.
struct B{
char a;
short b;
char c;
char d;
};
0x0000 |
0x00001 |
0x0002 |
0x0003 |
0x0004 |
0x0005 |
a |
x |
b |
b |
c |
d |
結構體B佔6個字節(0x0000~0x0005總內存爲6,爲short 類型的3倍)
struct C{
char a;
int b;
char c;
char d;
};
0x0000 |
0x00001 |
0x0002 |
0x0003 |
0x0004 |
0x0005 |
0x0006 |
0x0007 |
0x0008 |
0x0009 |
0x000A |
0x000B |
a |
x |
x
|
x |
b |
b |
b |
b |
c |
d |
x |
x |
x爲補齊的數據,結構體C佔12個字節 (0~B 佔12字節) ,結構體C的成員佔據10個字節,而結構體C的有效對齊值是其成員b的自身對齊值4,10不是4的倍數,故還需補齊兩個字節,此時結構體C佔據12個字節,是4的倍數
成員a的自身對齊值1,指定對齊值4,所以有效對齊值是1,地址0x0000是1的整數倍,故a存放起始地址是0x0000,佔一個字節;
成員b的自身對齊值4,指定對齊值4,所以有效對齊值是4,地址0x0004是4的整數倍,故b存放起始地址是0x0004,佔四個字節;
成員c的自身對齊值1,指定對齊值4,所以有效對齊值是1,地址0x0008是1的整數倍,故c存放起始地址是0x0008,佔一個字節;
成員d的自身對齊值1,指定對齊值4,所以有效對齊值是1,地址0x0009是1的整數倍,故d存放起始地址是0x0009,佔一個字節;
struct D{
char a;
double b;
char c;
char d;
};
0x0000 |
0x00001 |
0x0002 |
0x0003 |
0x0004 |
0x0005 |
0x0006 |
0x0007 |
0x0008 |
0x0009 |
0x000A |
0x000B |
0x000C |
0x000D |
0x000E |
0x000F |
a |
x |
x |
x |
b |
b |
b |
b |
b |
b |
b |
b |
c |
d |
Y |
Y |
結構體D佔16個字節,8的倍數
注意:由於結構體D的起始地址由a開始存儲,且按4字節的指定對齊值對齊,所以b從0x0004開始存儲。
若沒有指定按4字節對齊,起始地址需要按照從0x0008開始且總尺寸大小爲8的倍數,D結構體的實際佔據0~0x0011,總共爲17;不爲8的倍數,補齊至24,則sizeof(D)= 8+8+2+6, =24;
0x0000 |
0x00001 |
0x0002 |
0x0003 |
0x0004 |
0x0005 |
0x0006 |
0x0007 |
0x0008 |
0x0009 |
0x000A |
0x000B |
0x000C |
0x000D |
0x000E |
0x000F |
a |
x |
x |
x |
x |
x
|
x
|
x |
b
|
b |
b |
b |
b |
b |
b |
b |
0x0010 |
0x00011 |
0x0012 |
0x0013 |
0x0014 |
0x0015 |
0x0016 |
0x0017 |
0x0018(十進制24) |
0x0009 |
0x000A |
0x000B |
0x000C |
0x000D |
0x000E |
0x000F |
c |
d
|
x |
x |
x |
x |
x |
x |
x |
|