深入探索结构体(内存对齐)

结构体内存对齐

什么是内存对齐

内存对齐是数据在内存中按照特定规则排列的过程,通常是为了满足硬件平台访问数据的最佳方式,从而提高数据访问的效率。

首先我们先看几个例子在

#include <stdio.h>
int main()
{
	struct S1
		
	{
		char c1;
		int i;
		char c2;

	};

	printf("%d\n", sizeof(struct S1));
	//代码2
	struct S2
	{
		char c1;
		char c2;
		int i;
	};
	printf("%d\n", sizeof(struct S2));
	//- 结构体嵌套问题
		struct S3
	{
		char c1;
		struct S2 s2;
		double d;
	};
	printf("%d\n", sizeof(struct S3));
	return 0;
}

以上在vs环境中,两个结构体,相同数量,相同类型成员变量,只是顺序不同,那输出的是否一样呢

我们进行代码运行

得到的答案是否定的,

	
    struct S1
		
	{
		char c1;//1 byte
		//填充(3 byte)
		int i;//(4 bytes)
		char c2;//(1 byte)
		//填充(3 byte)
	};

	//代码2
	struct S2
	{
		char c1;//1 byte
		char c2;//(1 byte)
		// 填充(2 bytes)
		int i;//(4 bytes)
	};

因为对结构体是s1来说,

c1占1个字节,占0的字节,

进行为了使i对齐到4字节边界,会在c1i之间插入0到3个填充字节

b是int类型占4个字节,占从4~8的字节,

c2占1个字节,占9的字节

因为c2后没有其他成员,并且结构体的大小不是最大成员(int)的倍数

那么会在c2之后添加填充3个字节,以使整个结构体的大小成为int的倍数
对结构体B来说,

c1占用1个字节。
c2紧挨着c1后面,占用1个字节

接下来是int成员i。由于int通常需要对齐到4字节边界,而c1c2已经占用了2个字节

所以编译器可能会在这两个char之后插入2个字节的填充,以确保int成员i从(即4字节的边界)开始。

因为8已经是最大对齐数(int 4个字节)的整数倍,所以就不用填充了

对于代码三来说

因为c1占一个字节,struct S2 s2是取他的最大对齐数,说s2的最大对齐数是4,所以填充三个字节,然后占用4-12,到double d,因为double占用8个字节,要填充4个字节到16,占用16到24的字节,

结构体的对齐规则:

1.第一个成员在与结构体变量偏移量为0的地址处。
其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处

2.在32位系统上,VS2019的默认对齐通常遵循以下规则:char 的对齐数是 1 字节
short(或 short int)的对齐数通常是 2 字节
int、float、指针等的对齐数通常是 4 字节


3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。这里有一点需要澄清。结构体的大小通常是其所有成员大小(包括填充)的总和,并且会向上舍入到结构体内部最大对齐要求的整数倍。这并不意味着结构体的大小一定是所有成员对齐数的整数倍,而是结构体内部的最大对齐要求。
4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。嵌套的结构体确实会对其到自己的最大对齐数的整数倍处。但是,结构体的整体大小并不是所有最大对齐数的整数倍,而是其所有成员(包括嵌套结构体和其填充)大小的总和,并向上舍入到结构体自身的最大对齐数的整数倍。

如何修改对齐设置?

在C/C++中,可以使用特定的编译器指令(如#pragma pack)来修改默认的对齐设置。例如,#pragma pack(1)会设置1字节对齐,以减少填充并提高空间利用率,但可能会降低访问性能。

为什么存在内存对齐?

大部分的参考资料都是如是说的:

1. 平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能 在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2. 性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的 内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

总体来说:

结构体的内存对齐是拿空间来换取时间的做法

  • 15
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值