说明
不同类型的数据在内存中按照一定的顺序排列,不一定是顺序的一个一个接着排列
常见的我们定义结构体,结构体大小就不仅仅是每个成员占用大小之和
为什么需要内存对齐
CPU对内存的读取不是连续的,而是分块读取的,块的大小只能是 1、2、4、8 、16字节
当读取操作的数据未对齐,则需要两次总线周期来访问内存,因此性能会降低
某些硬件平台只能从规定的相对地址处读取特定类型的数据,否则产生硬件异常
根据对齐参数计算结构体占用大小
规则是:
-
第一个成员处于0偏移处
-
每个成员按照其类型大小和pack参数中较小的一个进行对齐
偏移地址必须能被对齐参数整除
结构体成员类型大小取其内部长度最大的数据成员作为其大小
-
结构体成员必须为所有对齐参数的整数倍
-
默认的pack参数是4
-
例子1
#include <stdio.h>
//默认pack对齐参数为4
struct Test1
{ // 对齐参数 起始地址 占用大小
char c1; // 1 0 1
short s; // 2 2 2
char c2; // 1 4 1
int i; // 4 8 4
};
//综上 Test1大小为 12
struct Test2
{ // 对齐参数 起始地址 占用大小
char c1; // 1 0 1
char c2; // 1 1 1
short s; // 2 2 2
int i; // 4 4 4
};
//综上 Test2 8
int main()
{
printf("sizeof(Test1) = %d\n", sizeof(struct Test1));
printf("sizeof(Test2) = %d\n", sizeof(struct Test2));
return 0;
}
例子2 带结构体
//默认pack 是 4
struct S1
{ //对齐参数 偏移地址 占用大小
short a; // 2 0 2
long b; // 4 4 4
};
//综上struct S1 大小为8
struct S2
{ //对齐参数 偏移地址 占用大小
char c; // 1 0 1
struct S1 d; // 4 4 8
double e; // 4 12 8
};
//综上struct S1 大小为20
int main()
{
printf("%d\n", sizeof(struct S1));
printf("%d\n", sizeof(struct S2));
return 0;
}
更改默认的pack参数
使用#pragma pack(1) 来实现
还是上面的第一个例子
#include <stdio.h>
//默认pack对齐参数为4
#pragma pack(1)
struct Test1
{ // 对齐参数 起始地址 占用大小
char c1; // 1 0 1
short s; // 1 1 2
char c2; // 1 3 1
int i; // 1 4 4
};
#pragma pack()
//综上 Test1大小为 8
#pragma pack(2)
struct Test2
{ // 对齐参数 起始地址 占用大小
char c1; // 1 0 1
char c2; // 1 1 1
short s; // 2 2 2
int i; // 2 4 4
};
#pragma pack()
//综上 Test2 8
int main()
{
printf("sizeof(Test1) = %d\n", sizeof(struct Test1));
printf("sizeof(Test2) = %d\n", sizeof(struct Test2));
return 0;
}