结构体struct 的内存对齐问题(c语言)

本文介绍了内存对齐的概念及原因,包括避免移植错误和提高读取效率,并通过多个结构体示例展示了对齐规则的应用。

内存对齐: 

 计算机把各种类型数据按照一定的规则在空间上排列,通过填充相应的字节把数据放在特定的地址上。

对齐原因:      

        (1)为了避免移植后计算机读取数据出错(各个硬件平台对存储空间的处理上有很大的不同,某些硬件平台只能在某些地址处去某些特定类型的数据,否则会出错)。

        (2)为了提高计算机取数的效率(比如有些平台每次读都是从偶地址开始,如果一个int型(32位系统)如果放在偶数地址开始的地方,那么一一个读周期就可以读出这32bit,而如果存放在奇数地址开始的地方,就需要2个读数周期,并对两次读出的结果的高低字节进行并凑才能得到该32bit数据。显然在读取效率上下降了很多)。

对齐规则:

(1)结构体变量的首地址能够被其最宽类型成员的大小整除;

(2)结构体成员的首地址是其大小的整倍数,若不是,编译器在该成员与前一个成员之间填充相应的字节;

(3)结构体的大小是其最大成员大小的整倍数,若不是,编译器在最后一个成员后填充相应的字节;


如图所示:       





#include <stdio.h>
struct A 
{
	char a;//1+3
	int b;//4
};//8

struct B 
{
	char a;//1+3
	int b;//4
	short c;//2+2
};//12

struct C
{
	short a;//2
	char b;//1+1
	int c;//4
};//8

struct D
{
	char a;//1+1
	short b;//2
	char c;//1+3
	int d;//4
};//12

struct E
{
	char a;//1
	char x;//保留1
	short b;//2
	int c;//4
};//8

struct I
	{
		char b;//1+3
		int c;//4
	}d;//8

struct II
{
	int a;
	struct I
	{
		char b;//1+3
		int c;//4
	}d;//8
};//12


int main()
{
	printf("sizeof(struct A): %d\n",sizeof(struct A));
	printf("sizeof(struct B): %d\n",sizeof(struct B));
	printf("sizeof(struct C): %d\n",sizeof(struct C));
	printf("sizeof(struct D): %d\n",sizeof(struct D));
	printf("sizeof(struct E): %d\n",sizeof(struct E));
	printf("sizeof(struct I): %d\n",sizeof(struct I));
	printf("sizeof(struct II): %d\n",sizeof(struct II));
	return 0;
}



在C语言中,结构体内存对齐机制是为了提高内存访问效率而设计的。内存对齐规则确保了结构体成员变量在内存中的存储位置符合一定的对齐要求,从而避免因访问未对齐数据而导致的性能下降或硬件异常。 ### 结构体内存对齐的基本规则 1. **成员对齐**:每个结构体成员变量的起始地址必须是其对齐数(alignment)的整数倍。对齐数通常是该类型大小的整数倍。例如,`int` 类型通常需要 4 字节对齐,`double` 类型通常需要 8 字节对齐。 2. **结构体总大小对齐**:结构体的总大小必须是其内部成员中最大对齐数的整数倍。这意味着在最后一个成员之后可能会有填充字节(padding),以确保整个结构体的大小满足对齐要求。 3. **编译器对齐设置**:不同的编译器可能会有不同的默认对齐方式,也可以通过编译器指令(如 `#pragma pack`)来改变对齐方式。 ### 示例说明 假设有一个结构体如下: ```c struct Example { char a; // 1 byte int b; // 4 bytes short c; // 2 bytes }; ``` 按照默认的对齐规则,`char` 类型的对齐数为 1,`int` 类型的对齐数为 4,`short` 类型的对齐数为 2。 - `a` 占用 1 字节,起始地址为 0。 - `b` 需要 4 字节对齐,因此从地址 4 开始,占用 4 字节(地址 4~7)。 - `c` 需要 2 字节对齐,因此从地址 8 开始,占用 2 字节(地址 8~9)。 由于结构体的总大小必须是最大对齐数(这里是 `int` 的 4 字节对齐)的整数倍,因此结构体的总大小为 12 字节(地址 0~11),其中 `a` 后面填充了 3 字节以保证 `b` 的起始地址是 4 的倍数。 ### 自定义对齐方式 可以通过 `#pragma pack` 指令来改变结构体对齐方式。例如: ```c #pragma pack(1) // 设置为 1 字节对齐 struct PackedExample { char a; int b; short c; }; #pragma pack() // 恢复默认对齐方式 ``` 在这种情况下,结构体将不会有填充字节,总大小为 1 + 4 + 2 = 7 字节。 ### 结构体对齐的影响 - **性能影响**:合理的内存对齐可以提高程序的运行效率,尤其是在处理大量数据时。 - **可移植性影响**:不同的平台和编译器可能有不同的对齐规则,因此在跨平台开发时需要注意对齐问题。 ### 总结 结构体内存对齐机制确保了数据在内存中的高效访问,同时通过填充字节来满足对齐要求。理解这些规则有助于优化程序性能和内存使用,特别是在嵌入式系统或高性能计算中尤为重要。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值