C语言地址对齐分析与示例
1.什么是地址对齐
计算机硬件设计的特点决定了这样一个事实:CPU在访问内存时,如果其地址是机器字长的整数倍,那么访问的效率就会比较高。这样的现象就称为地址对齐(也有说内存对齐)。并且有的CPU根本就无法访问那些地址没有对齐的内存单元(这时需要使用软件模拟地址对齐,操作效率会大为降低)。而在一般32位机上,地址对齐的界限是32/8=4的整数倍。
2.地址对齐与执行效率
字符串长度排序c语言为了提高程序的执行效率,编译器会努力让所有变量的地址符合地址对齐的原则。这在结构体中体现的比较明显,例如如下的结构体定义:
struct S1{
char c1;
char c2;
char c3;
int x;
char c4;
};
如果我们使用sizeof关键字求该结构体的大小,就会发现sizeof(S1)并不等于其包含各域的大小之和。这本示例中sizeof(S1)=12而不是8。这是因为编译器为了使结构体中数据能够满足地址对齐而自动的加入了空闲字节。这些空闲字节没有被任何数据成员使用,它们存在的目的只是为了满足内存地址能够对齐。
我们可以用如下图解释上述现象:
4n4(n+1)4(n+2)
1111413
整个结构体【总计12字节】
如果我们将S1结构体中int x和char c4的位置互换,则sizeof(S1)就会变为8。大家可按照上述分析方法考虑其原因。
3.编译器,请不要自作主张
自动对齐的方式虽然能够提高执行效率,然而却浪费了空间(这貌似也显示了一些时空一致性的思想:))。真是鱼和熊掌不可得兼。那么当我们在意的是空间而不是时间的时候,自动的地址对齐就不那么受欢迎了。于是我们可以采用下面的办法让编译器“老实点”。
#pragma pack(1)/*将地址对齐的界限设定为1*/
struct S1{
char c1;
char c2;
char c3;
int x;
char c4;
};
这时S1的大小就只有8个字节了(因为我们将地址对齐的界限设定为1了,当然就不再需要空闲字节去补齐内存了)。如果想在S1以后的定义中仍使用默认的对齐界限,只需在S1的定义之后加上#pragma pack()就行了。
另外GNU C支持的结构体扩展属性也可以实现#pragma pack(1)的效果:
struct S1{
char c1;
char c2;
char c3;
int x;
char c4;
}__attribute__((packed));
【提示:如果你想在PC上测试GNU C支持的这种做法,首先要确定你的编译器是GNU的】

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。