一、结构体对齐概念
在结构中,编译器为结构的每个成员按其自然边界(alignment)分配空间。各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。为了使CPU能够对变量进行快速的访问,变量的起始地址应该具有某些特性,即所谓的”对齐”。比如4字节的int型,其起始地址应该位于4字节的边界上,即起始地址能够被4整除。
所以相邻两个成员的地址不一定是“紧挨着”,这概念对于处理长串数据很重要,要避免有效数据放进了结构体的无效地址区。
*几个重要概念:
1.数据类型自身的对齐值:
对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4,单位字节。
2.结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值。
3.指定对齐值:#pragma pack (value)时的指定对齐值value。
4.数据成员、结构体和类的有效对齐值:如果未指定对齐值,以自身对齐值为准,如果定义了,则是自身对齐值和指定对齐值当中最小的那个。(对于linux来说,通常未指定对齐值,所以只需考虑自身对齐值,当然最好写测试程序验证下)
有了这些值,我们就可以很方便的来讨论具体数据结构的成员和其自身的对齐方式。有效对齐值N是最终用来决定数据存放地址方式的值,最重要。有效对齐N,就是表示“对齐在N上”,也就是说该数据的"存放起始地址%N=0"。
结构体本身也要根据自身的有效对齐值圆整(就是结构体成员变量占用总长度需要是结构体的有效对齐值的整数倍。
struct stu1{
char sex;
long long length;
char name[10];
}; //size=1+7+8+10+6=32(自身对齐值8)
struct stu2{
char sex;
int length;
char name[10];
};//size=1+3+4+10+2=20(自身对齐值4)
struct stu3{
char sex;
short int length;
char name[10];
};//size=1+1+2+10=14(自身对齐值2)
关于结构体嵌套的举例
struct _stu{
char flag;
struct stu3 my_stu;//当做一个整体来考虑
char age;
}stu_second;//size=1+1+14+1+1=18,有效对齐值为2,此处my_stu成员的起始地址应是2的整数倍
关于结构体圆整的举例如下:
struct B
{
char b;
int a;
short c;
};
分析:假设B从地址空间0x0000开始排放,根据结构体圆整的要求,0x0009到0x0000总共10字节,(10+2)%4=0。所以0x0000A到0x000B也为结构体B所占用。故B从0x0000到0x000B共有12个字节,sizeof(struct B)=12。
对结构体圆整必要性的分析:试想如果我们定义了一个结构B的数组,那么第一个结构起始地址是0没有问题,但是第二个结构呢?按照数组的定义,数组中所有元素都是紧挨着的,如果我们不把结构的大小补充为4的整数倍,那么下一个结构的起始地址将是0x0000A,这显然不能满足结构的地址对齐了,因此我们要把结构补充成有效对齐大小的整数倍.
二、更改C编译器的缺省字节对齐方式
1、在缺省情况下,C编译器为每一个变量或是数据单元按其自然边界条件分配空间。一般地,可以通过下面的方法来改变缺省的对界条件:
· 使用伪指令#pragma pack (n),C编译器将按照n个字节对齐。
· 使用伪指令#pragma pack (),取消自定义字节对齐方式。
另外,还有如下的一种方式:
· __attribute((aligned (n))),让所作用的结构成员对齐在n字节自然边界上。
· __attribute__ ((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。
2、关于__attribute__选项
我们可以按照自己设定的对齐大小来编译程序,GNU使用__attribute__选项来设置,比如我们想让刚才的结构按1字节对齐,我们可以这样定义结构体
struct stu{
char sex;
int length;
char name[10];
}__attribute__ ((aligned (1)));
struct stu my_stu;
则sizeof(my_stu)可以得到大小为15。
上面的定义等同于
struct stu{
char sex;
int length;
char name[10];
}__attribute__ ((packed));
struct stu my_stu;
__attribute__((packed))得变量或者结构体成员使用最小的对齐方式,即对变量是一字节对齐,对域(field)是位对齐.
参考资料