先介紹三個概念:自身對齊值、指定對齊值、有效對齊值。
自身對齊值:數據類型本身的對齊值,例如char類型的自身對齊值是1,short類型是2;
指定對齊值:編譯器或程序員指定的對齊值,32位單片機的指定對齊值默認是4;
有效對齊值:自身對齊值和指定對齊值中較小的那個。
對齊有兩個規則:
1、不但結構體的成員有有效對齊值,結構體本身也有對齊值,這主要是考慮結構體的數組,對於結構體或者類,要將其補齊為其有效對齊值的整數倍。結構體的有效對齊值是其最大數據成員的自身對齊值;
2、存放成員的起始地址必須是該成員有效對齊值的整數倍。
舉四個例子
假如結構體起始地址是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.
結構體A的存儲結構如下,其中Y是根據規則1補齊的字節,x是規則2補齊的字節。
0x0000 |
0x00001 |
0x0002 |
0x0003 |
a |
b |
c |
d |
根據以上規則可以知道其他結構體的存儲結構:
結構體B占6個字節
0x0000 |
0x00001 |
0x0002 |
0x0003 |
0x0004 |
0x0005 |
a |
x |
b |
b |
c |
d |
結構體C占12個字節
成員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,占一個字節;
結構體C的成員占據10個字節,而結構體C的有效對齊值是其成員b的自身對齊值4,10不是4的倍數,故還需補齊兩個字節,此時結構體C占據12個字節,是4的倍數
如下:
0x0000 |
0x00001 |
0x0002 |
0x0003 |
0x0004 |
0x0005 |
0x0006 |
0x0007 |
0x0008 |
0x0009 |
0x000A |
0x000B |
a |
x |
x |
x |
b |
b |
b |
b |
c |
d |
Y |
Y |
結構體D占16個字節
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 |
代碼驗證如下: