本文以gcc version 4.4.3 ,64位x86环境为例,来分析结构体中各成员如何进行对齐。
我们要注意两个方面:
1)结构体成员变量对存放的起始地址有要求
2)结构体变量占用的总长度也有要求
结构体对齐规则如下:
1、数据成员最终的存放地址:对齐在自身类型长度和#pragma pack(value)指定值中较小的值上。
例如char型, 其占用1个字节, #pragma pack(4)指定值是4, 那么char类型本身存放的起始地址是1个字节对齐,也就是其所存放的
起始地址要求被1除尽. 64位系统long 类型占用8个字节,如果#pragma pack(4),那么两者取小值,即4,那么long起始地址是4字节对齐。
2、结构体的总长度:对齐在成员类型长度最大的值和pragma pack(value)指定值中较小的值上。
结构体最终的总长度,应取成员类型长度最大值与#pragma pack(value)指定值中较小的值的整数倍。
看下面几个例子:(当前gcc version 4.4.3,64位x86环境下,8位对齐,可使用#pragma pack(value)修改)
例1:
#include <stdio.h>
#pragma pack(push)
typedef struct CHIP
{
char a;
int b;
char c;
long d;
}test;
void main()
{
test h;
printf("size of struct = %d\n",sizeof(h));
}
分析: pragma pack(push),系统default对齐为8位
char a成员,char类型长度1,pragma pack(push) (default为8),取小的1,其存储位置0x00000000
int b成员,int类型长度为4,pragma pack(8),两者取相对较小值为4,因此int的存储地址需要4字节对齐,在0x00000004~0x00000007
char c成员,char 类型长度为1, 即存储位置为0x00000008 ~ 0x00000009
long c成员,long类型长度为8, pragma pack(8), 需要8位对齐,因此c的存储位置为0x00000010 ~ 0x00000017
最终结构体的size需要在类型长度最大的值即long (长度为8) 和#pragma pack(push) (当前环境default为8)指定值中较小的对齐,
即8位对齐,因此最终长度还是24.
例2, 修改code如下
#include <stdio.h>
#pragma pack(4)
typedef struct CHIP
{
char a;
int b;
char c;
long d;
}test;
void main()
{
test h;
printf("size of struct = %d\n",sizeof(h));
}
说明: #pragma pack(4)指定4位对齐
char a 0x00000000 ~ 0x00000000
int b 0x00000004 ~ 0x00000007
char c 0x00000008 ~ 0x00000008
long d 0x0000000C ~ 0x00000013
结构体总长度为20,4位对齐最终的结构体size为20
例3, 修改code如下
#include <stdio.h>
typedef struct CHIP
{
long b;
char c;
char d;
}test;
void main()
{
test h;
printf("size of struct = %d\n",sizeof(h));
}
说明: 未指明 #pragma pack() default 为8 byte对齐
long b 0x00000000 ~ 0x00000007
char c 0x00000008 ~ 0x00000008
char d 0x00000009 ~ 0x00000009
补齐 0x0000000A ~ 0x000000F
结构体总长度为16,8位对齐最终的结构体size为16
可参考另一篇转载博文 《失落的C语言结构体封装艺术》 http://blog.youkuaiyun.com/chrovery/article/details/18989779