【开发笔记#3】结构体字节对齐

428 阅读3分钟

结构体对齐原则

1.针对整个内存空间

  • 结构体变量的首地址能够被其最宽基本类型成员的大小所整除。
typedef struct Test {
    char a;
    short b;
    int c;
    double d;	//最宽成员占8字节
} Test;

首地址打印

Test t;
printf("%p\n",&t); //打印结果首地址可以整除8(最宽成员所占大小)

2.针对结构体内部成员

  • 1)、结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍;
  • 2)、结构体嵌套结构体,按内部结构体宽度最宽的基本类型成员大小来对齐;
  • 3)、按对齐原则,在未占用空间进行填充。
typedef struct Test1 {
    int a;		// 0~3,共4字节,偏移地址是4的0倍
    char b;		// 4,共1字节,偏移地址是1的4倍
    double c;		// 8~15,共8字节,偏移地址是8的1倍,故5~7需要填充
    short d;		// 16~17,共2字节,偏移地址是2的8倍
} Test1;

typedef struct Test2 {
    char b;		// 0,共1字节,偏移地址是1的0倍
    double c;		// 8~15,共8字节,偏移地址是8的1倍,故1~7需要填充
    short d;		// 16~17,共2字节,偏移地址是2的8倍
    int a;		// 20~23,共4字节,偏移地址是4的5倍,故18~19需要填充
} Test2;

typedef struct Test3 {
    char b;		// 0,共1字节,偏移地址是1的0倍
    double c;		// 8~15,共8字节,偏移地址是8的1倍,故1~7需要填充
    short d;		// 16~17,共2字节,偏移地址是2的8倍
    struct Test t;	// 24~39,共16字节,偏移地址是8(Test最宽成员大小为8)的3倍,故18~23需要填充
    int a;		// 40~43,共4字节,偏移地址是4的10倍
} Test3;

3.针对结构体整体

  • 1)、结构体的总大小为结构体最宽基本类型成员大小的整数倍;
  • 2)、若最后所占空间小于整数倍,则在最末一个成员之后填充字节。
typedef struct Test1 {
    int a;		// 0~3
    char b;		// 4
    double c;		// 8~15
    short d;		// 16~17
} Test1;		// 0~17总宽度18,最大成员为8,3*8=24,故结构体总宽度为24,18~23需要填充

typedef struct Test2 {
    char b;		// 0
    double c;		// 8~15
    short d;		// 16~17
    int a;		// 20~23
} Test2;		// 0~23总宽度为24,最大成员为8,刚好是8的倍数,故结构体总宽度为24,不需要填充

typedef struct Test3 {
    char b;		// 0,共1字节,偏移地址是1的0倍
    double c;		// 8~15,共8字节,偏移地址是8的1倍,故1~7需要填充
    short d;		// 16~17,共2字节,偏移地址是2的8倍
    struct Test t;	// 24~39,共16字节,偏移地址是8(Test最宽成员大小为8)的3倍,故18~23需要填充
    int a;		// 40~43,共4字节,偏移地址是4的10倍
} Test3;		// 0~43总宽度44,最大成员为8,6*8=48,故结构体总宽度为48,44~47需要填充