结构体内存对齐,主要是为了CPU能更快速的提取数据
所谓的对齐,指结构体及其成员的内存起始地址address应为要对齐大小X的倍数,
即address = kX
假设 n 为编译器设定的对齐大小, item为结构体中成员类型,那么实际对齐的大小值,
计算如下:
X = min(n, sizeof(item))
-------------------------------------------------------
举例:
例1:
enum ENUM_DATA{IntData, CharData, LongData};
struct Item
{
char ItemChar1[30];
ENUM_DATA ItemEnum;
char ItemChar2[50];
int ItemInt;
};
sizeof(struct Item)等于多少?
分析如下:
1.结构体模式模式按成员中最大长度类型进行内存对齐,
struct Item中最大长度类型为int,长度为4
2.假设第一成员的起始地址为0,那么:
ItemChar1 的类型长度为1,根据X = min(n, sizeof(ItemChar1)),即X = min(4, 1) = 1,按1对齐
所以,内存地址空间范围为 0~29, 占30个Byte;
ItemEnum 的类型长度为4,根据X = min(n, sizeof(ItemEnum)),即X = min(4, 4) = 4,按4对齐
由于ItemChar1的结尾内存地址为29,所以下一个成员应该从30开始,
但是30不是4的倍数,往后偏移到32才是4的倍数,
所以ItemEnum的起始内存地址应该是32,
所以,内存地址空间范围为 32~35, 占4个Byte;
ItemChar2 的类型长度为1, X = min(4, 1) = 1
所以,内存地址空间范围为 36~85, 占50个Byte;
ItemInt 的类型长度为4,X = min(4, 4) = 4
起始地址应该是86,但是86非4的倍数,最靠近的88才是4的倍数,
所以起始地址偏移到88的位置
所以,内存地址空间范围为 88~91, 占4个Byte;
3. 由上一步计算得到结构体的内存空间范围为0~91,即大小为92,
而92已经是4的倍数,即所谓的已经对齐
所以该结构体的大小: sizeof(struct Item)等于92
-------------------------------------------------------
例2:
struct A{
int i;
int j;
short s;
char c;
};
分析如下:
1.结构体A的最大长度类型int,大小为4
2.假设起始地址为0
i 的类型int, 大小为4, min(4, 4) = 4, 按4对齐,内存地址空间为 0~3
j 的类型int, 大小为4, min(4, 4) = 4, 按4对齐,内存地址空间为 4~7 (4已是4的倍数)
s 的类型short,大小为2,min(4, 2) = 2, 按2对齐,内存地址空间为 8~9 (8已是2的倍数)
c 的类型char, 大小为1, min(4, 1) = 1, 按1对齐,内存地址空间为 10 (10已是1的倍数)
3. 结构体A的地址空间范围为0~10, 大小为11,
但由于要按4对齐,11非4的倍数,最靠近的12才是
所以结构体A的大小应该是12
-------------------------------------------------------
例3:
struct A
{
char a;
int b;
double c;
char d;
};
1. 结构体最大长度类型double,长度为8
2. 假设结构体起始地址为0
a 的类型char大小为1,1小于8,按1对齐,地址空间范围为 0
b 的类型int 大小为4,4小于8,按4对齐,
由于接下来的起始地址1不是4的倍数,所以取4做起始地址
即b的地址空间范围应该是4~7
c 的类型double 大小为8,8等于8,按8对齐,
接着的起始地址应该是8,已经是8的倍数,
所以c的地址空间范围应该是 8~15
d 的类型char大小为1,1小于8,按1对齐,地址空间范围16
3. 结构体地址空间范围0~16, 大小为17,
17不是8的倍数,最靠近的为8的倍数的数应该是24,
所以该结构体大小为24
-------------------------------------------------------
测试:
test.c
#include <stdio.h>
struct st_a {
int a;
char b;
char c;
};
struct st_b {
char b;
short c;
int a;
};
struct st_c {
char b;
int a;
short c;
};
int main(int argc, char* argv[])
{
struct st_a a;
struct st_b b;
struct st_c c;
printf("st_a size:%d\n", sizeof(a));
printf(" &a:%ld\n", &a.a);
printf(" &b:%ld\n", &a.b);
printf(" &c:%ld\n", &a.c);
printf("st_b size:%d\n", sizeof(b));
printf(" &b:%ld\n", &b.b);
printf(" &c:%ld\n", &b.c);
printf(" &a:%ld\n", &b.a);
printf("st_c size:%d\n", sizeof(c));
printf(" &b:%ld\n", &c.b);
printf(" &a:%ld\n", &c.a);
printf(" &c:%ld\n", &c.c);
return 0;
}
gcc -o t test.c
./t
输出:
st_a size:8
&a:140733530861264
&b:140733530861268
&c:140733530861269
st_b size:8
&b:140733530861248
&c:140733530861250
&a:140733530861252
st_c size:12
&b:140733530861232
&a:140733530861236
&c:140733530861240
参考文章: