数据对齐
1、为什么需要数据对齐?
最早在8位CPU的时代,是没有数据对齐的需求的。当CPU发展到16位、32位或者64位时代时,才有了数据对齐的需求,因为CPU一次取4个字节的数据(以32位CPU为例),也就是说CPU是这么取数据的:0x00000000 , 0x00000004 , 0x00000008 ,0x0000000C …
如果把 int a = 0x12345678 存储在地址 0x00000000 , 那么CPU只需一次就能取到变量a;
地址 | 值 |
---|---|
0x00000000 | 0x12 |
0x00000001 | 0x34 |
0x00000002 | 0x56 |
0x00000003 | 0x78 |
如果把 int a = 0x12345678 存储在地址 0x00000003,那么CPU就需要2次才能取到变量a,第一次CPU从0x00000000取到数值0x- - - - - -12,第二次CPU从0x00000004取到数值0x345678- - ,最后CPU把两次取到的值合并成变量a(0x12345678)
地址 | 值 |
---|---|
0x00000000 | 0x– |
0x00000001 | 0x– |
0x00000002 | 0x– |
0x00000003 | 0x12 |
0x00000004 | 0x34 |
0x00000005 | 0x56 |
0x00000006 | 0x78 |
0x00000007 | 0x– |
所以从上面的阐述中可以看出,在16位、32位或者64位CPU的时代,数据对齐是有意义的。
注:
1、为什么32位CPU一次取4个字节的数据呢?去研究一下ARM处理器外接的DDR RAM就明白了。
2、这里说的是一次取4个字节的数据,不是说4字节对齐,数据对齐的概念见下文。
3、本文仅通俗的解释数据对齐问题。
2、什么是数据对齐
数据对齐的意思是说:地址值为大小的整数倍。
例如,4字节(字)对齐的合法地址为0x00000000 , 0x00000004 , 0x00000008 , 0x0000000c , 0x00000010 … 0x00001004等;
2字节(半字)对齐的合法地址为0x00000000 , 0x000000002 , 0x00000004 , 0x00000006 … 0x00001002等。
1字节的对齐的合法地址为0x00000000 , 0x000000001 , 0x00000002 , 0x00000003 … 0x00001009等。
自身对齐值(所占字节数)
数据类型 | 自身对齐值 |
---|---|
char | 1 |
short | 2 |
int | 4 |
结构体的自身对齐值:其成员中自身对齐值最大的那个值
指定对齐值
数据对齐是C编译器默认的行为,一般C编译器默认4字节对齐,这就是指定对齐值。
有效对齐值
有效对齐值 = min( 自身对齐值,指定对齐值 )
3、实例分析
struct a{
char a;
short b;
char c,d,e;
short f;
};
struct b{
char a;
char c,d,e;
short b;
short f;
int g;
char h;
};
// the result is 10 16
printf("%d %d\n",sizeof(struct a) , sizeof(struct b));
对于struct a的分析(数据在内存中是连续存储的)
char a; 自身对齐值为1,设定对齐值为4,所以有效对齐值为1,所以合法地址为0x00000000
short b; 自身对齐值为2,设定对齐值为4,所以有效对齐值为2,所以合法地址为0x00000002
char c,d,e; 自身对齐值均为1,设定对齐值为4,所以有效对齐值均为1,所以合法地址分别为0x00000004,0x00000005,0x00000006
short g; 自身对齐值为2,设定对齐值为4,所以有效对齐值为2,所以合法地址为0x00000008
结构体的成员变量要对齐排放,结构体本身也要根据自身的有效对齐值圆整(就是结构体成员变量占用总长度需要是对结构体有效对齐值的整 数倍
struct a 中自身对齐值最大为2,所以struct a的打大小就必须是2的整数倍,因为其成员变量的总大小是12,正好是2的倍数,所以sizeof(struct a) 是12。
对于struct b的分析(数据在内存中是连续存储的)
char a,c,d,e; 自身对齐值均为1,设定对齐值为4,所以有效对齐值均为1,所以合法地址分别为0x00000000,0x00000001,0x00000002,0x00000003
short b; 自身对齐值为2,设定对齐值为4,所以有效对齐值为2,所以合法地址为0x0000004
short f; 自身对齐值为2,设定对齐值为4,所以有效对齐值为2,所以合法地址为0x00000006
short g; 自身对齐值为2,设定对齐值为4,所以有效对齐值为2,所以合法地址为0x00000008
char h; 自身对齐值为1,设定对齐值为4,所以有效对齐值为1,所以合法地址为0x0000000C
结构体的成员变量要对齐排放,结构体本身也要根据自身的有效对齐值圆整(就是结构体成员变量占用总长度需要是对结构体有效对齐值的整 数倍
struct b 中自身对齐值最大为4,所以struct a的打大小就必须是4的整数倍,因为其成员变量的总大小是14,不是4的倍数,所以struct b的大小要根据其自身有效对齐值(4)圆整,所以sizeof(struct b) 是16。