pragma pack和内存对齐
程序员文章站
2022-05-05 10:05:18
...
概述
内存对齐和CPU有关系,可以认为内存对齐的大小就是CPU一次读取内存的大小,例如32CPU一次读取4字节,那么内存的对齐方式就4字节,64位就是8字节。本质上是保证CPU使用尽量少的次数将某一个变量取出来。关于结构体内存对齐的方式,只需要把握两点即可:
- 每个成员变量的对齐原则,即成员的偏移量计算。参见成员对齐原则。
- 整个结构体的对齐原则,即结构大小的计算。参见整体对齐原则。
pragma pack(n)的作用
上面说了,编译默认对齐方式是4字节(32位系统)或者8字节(64)位系统,但是通过pragma pack可以自己定义内存的对齐方式。
#pragma pack(n) // n = 1,2,4,8,16......
实例
#include <stdio.h>
//#pragma pack(2)
//#pragma pack(4)
struct node{
char f;
int e;
short a;
char d;
};
int main(void)
{
node n;
printf("len=%d\n", sizeof(node));
return 0;
}
// 输出:
当 #pragma pack(2) 时, len = 10
当 #pragma pack(4) 时, len = 12
当 #pragma pack(8) 时, len = 12
当 不使用#pragma pack(n) 时, len = 12
内存对齐的原则
对照上面的实例,下面讲解具体原则。
1、成员对齐原则
对于结构体的各个成员,第一个成员的偏移量是0,后面的成员其当前偏移量必须是当前成员类型大小的整数倍。
上面的案例中,在默认的对齐方式中,e的偏移量必须是4的倍数,因为e占4个字节,所以f要补齐3个字节,使e偏移量为4。f偏移量为0,a的偏移量为2的倍数是8,d的偏移量为1的倍数,为11。
2、整体对齐原则
结构体内所有数据成员各自内存对齐后,结构体本身还要进行一次内存对齐,保证整个结构体占用内存大小是结构体内最大数据成员的最小整数倍。
上面可知,d的偏移量为11,其实11个字节就可以存下,但是整体的大小必须是最大成员e的倍数,因此至少为12,d需要补齐一个字节。
3、自定义对齐方式
即使用#pragma pack(n)预编译指令。
如果程序中使用#pragma pack(n),则忽略上面的两个原则。只需遵循以下面两个新原则:
1、成员对齐
- 当 n >= 成员变量的大小, 该变量的偏移量仍然是自身大小的整数倍。
- 当 n < 成员变量的大小, 该变量的偏移量是n的整数倍。
2、整体对齐
- 当 n >= 最大成员变量的大小, 整个结构体大小仍然是最大成员的整数倍。
- 当 n < 最大成员变量的大小, 整个结构体大小是n的整数倍。