C语言结构体字节对齐总结

首先说说为什么要对齐。为了提高效率,计算机从内存中取数据是按照一个固定长度的。以32位机为例,它每次取32个位,也就是4个字节。字节对齐有什么好处?以int型数据为例,如果它在内存中存放的位置按4字节对齐,也就是说1个int的数据全部落在计算机一次取数的区间内,那么只需要取一次就可以了。如果不对齐,很不巧,这个int数据刚好跨越了取数的边界,这样就需要取两次才能把这个int的数据全部取到,这样效率也就降低了。

其实不同的编译器,会对字节对齐进行不同的优化。这里以编译器不对字节对齐做任何优化为前提来讨论。

以下例子均在Ubuntu10.04下按gcc -O0命令编译。

一、原则:

1:当未明确指定时,以结构体中最长的成员的长度为其有效值。

如:

struct AA{

    char a;

    int b;

    char c; 

}aa;

char的字对齐长度为1,所以可以在任何地址开始,但是,int自对齐长度为4,必须以4的倍数地址开始。所以,尽管1-3空着,但b也只能从4开始。再加上c后,整个结构体的总长度为9,结构体的有效对齐值为其中最大的成员即int的长度4,所以,结构体的大小向上扩展到12,即9-11的地址空着。

当结构体中包含其他的符合类型时:

数组 :按照基本数据类型对齐,第一个对齐了后面的自然也就对齐了。 

联合 :按其包含的长度最大的数据类型对齐。 

结构体: 结构体中每个数据类型都要对齐。


2:当用#pragma pack(n)指定时,以n和结构体中最长的成员的长度中较小者为其值。

这个宏定义既限制了整个结构体的对齐方式,也限制了结构体内部的变量的对齐方式。

#pragma pack(2)

struct AA{

    char a;

    int b;

    char c; 

}aa;

printf("sizeof aa = %d\n",sizeof(aa)); 结果是8。

假如地址从0开始算起,则变量a占据了头两个字节,变量b占据了接着的4个字节,变量c占据了最后的两个字节。

在这里,变量b按2字节对齐方式,整个结构体也按2字节对齐。

当被#pragma pack限制的结构体1里面包含未被限制的结构体2,则未被限制的结构体2内部按它自己的

规则来决定对齐方式,结构体1把结构体2当作一个一般的变量来处理。例如:

struct N {

short a;

int b;

int c;

};

#pragma pack(2)

struct S {

short a;

int b;

int c;

struct N d;

};

struct N cc;

struct S bb;


printf("sizeof cc = %d\n",sizeof(cc));

printf("sizeof bb = %d\n",sizeof(bb));

打印结果是:

sizeof cc = 12

sizeof bb = 22

因为结构体struct N 没有被宏修饰,所以变量cc内部是按规则1来决定对齐方式,也就是按4字节对齐。

struct S被宏修饰,里面的变量需要和宏比较一下,才能得到各自的对齐方式。里面的变量类型最少占2字节,

最多占12字节,所以里面的变量都按2字节对齐,整个结构体也按2字节对齐。变量d虽然作为一个整个,在

struct S里面按2字节对齐,但它内部还是按4字节对齐,因此变量d还是占据12字节。整个结构体一共占22字节。


3:当用__attribute__ 宏来指定长度时,强制按照此值为结构体的有效对齐。

__attribute__是GNU C的特点,详细请看

http://www.cnblogs.com/astwish/p/3460618.html

__attribute__只修饰该结构体整体,结构体内部的变量是不修饰的。

从连接里面的

printf("oo=%d,xx=%d \n", sizeof(oo),sizeof(xx));
打印结果还可以知道,虽然sizeof(oo)为8,也就是struct o占8个字节,但它是按4字节对齐的。


4:位变量还没研究,以后再补充。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值