结构体字节对齐

本文深入解析了字节对齐的概念,解释了不同硬件平台对存储空间处理的差异,以及字节对齐如何影响数据访问效率。文章详细介绍了字节对齐的原则,以及如何在C编译器中设置不同的对齐方式,提供了代码示例,帮助读者理解字节对齐的实际应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、什么是字节对齐

现代计算机中,内存空间按照字节划分,理论上可以从任何起始地址访问任意类型的变量。但实际中在访问特定类型变量时经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序一个接一个地存放,这就是对齐。

2、字节对齐的原因和作用

不同硬件平台对存储空间的处理上存在很大的不同。某些平台对特定类型的数据只能从特定地址开始存取,而不允许其在内存中任意存放。例如Motorola 68000 处理器不允许16位的字存放在奇地址,否则会触发异常,因此在这种架构下编程必须保证字节对齐。

但最常见的情况是,如果不按照平台要求对数据存放进行对齐,会带来存取效率上的损失。比如32位的Intel处理器通过总线访问(包括读和写)内存数据。每个总线周期从偶地址开始访问32位内存数据,内存数据以字节为单位存放。如果一个32位的数据没有存放在4字节整除的内存地址处,那么处理器就需要2个总线周期对其进行访问,显然访问效率下降很多。

因此,通过合理的内存对齐可以提高访问效率。为使CPU能够对数据进行快速访问,数据的起始地址应具有“对齐”特性。比如4字节数据的起始地址应位于4字节边界上,即起始地址能够被4整除。

此外,合理利用字节对齐还可以有效地节省存储空间。但要注意,在32位机中使用1字节或2字节对齐,反而会降低变量访问速度。因此需要考虑处理器类型。还应考虑编译器的类型。在VC/C++和GNU GCC中都是默认是4字节对齐。

3、字节对齐原则

 * 1、结构体变量的首地址能被对齐数整除
 * 2、每个成员相对首地址的offset都是对齐数的整数倍
 * 3、结构体总的大小为对齐数的整数倍
 * 4、不同的编译器对齐数不一样,gcc的对齐数是4,不是max_width

4、设置对齐方式

主要是更改C编译器的缺省字节对齐方式。

在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。一般地,可以通过下面的方法来改变缺省的对界条件:

使用伪指令#pragma pack(n):C编译器将按照n个字节对齐;
使用伪指令#pragma pack(): 取消自定义字节对齐方式。

另外,还有如下的一种方式(GCC特有语法):

__attribute__((aligned (n))): 让所作用的结构成员对齐在n字节自然边界上。如果结构体中有成员的长度大于n,则按照最大成员的长度来对齐。
__attribute__ ((packed)): 取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。

4、代码示例

/**
 * 32位OS默认按4字节对齐
 */
struct A{
	int a;
	char b;
	short c;
}AT;

struct B{
	char b;
	int a;
	short c;
}BT;

#pragma pack(2) /* 按2字节对齐 */
struct C{
	char b;
	int a;
	short c;
}CT;
#pragma pack()

#pragma pack(1) /* 按1字节对齐 ,则大小为类型长度总和*/
struct D{
	char b;
	int a;
	short c;
}DT;
#pragma pack()

#define GNUC_PACKED __attribute__((aligned(2)))  /* 按2字节对齐 */
struct KT{
     char  b;
     int   a;
     short c;
}GNUC_PACKED;

struct Tone{
	int m1;
	char m2;
	float m3;
	union Tun{
		char u1[5];
		int u2[2];
	}UT;
	double m4;
}ToneT;

void testStSize()
{
	printf("%d,%d\n",sizeof(AT),sizeof(BT));//8,12
	printf("%d,%d\n",sizeof(CT),sizeof(DT));//8,7
	printf("%d\n",sizeof(ToneT));//32
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值