结构体内存对齐(你可能不知道但很重要的知识)

先看一道题

#include<stdio.h>
struct s1 {
	char a;
	int b;
	char c;
};
typedef struct s2 {
	char a;
	char c;
	int b;	
};
int main() {
	printf("%d\n",sizeof(struct s1));
	printf("%d\n", sizeof(struct s2));

	return 0;
}

答案:

如果你这道题做错了,不理解其中原理,不知道答案为什么是这样,说明你喜欢玩原神,你喜欢玩原神,说明你这辈子有了(doge)

好了,说正事,说明这篇文章对你很重要,你应该看下去。

首先,你需要掌握结构体的对齐规则:

1.结构体的第⼀个成员对⻬到和结构体变量起始位置偏移量为0的地址处

2.其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处。

对⻬数=编译器默认的⼀个对⻬数与该成员变量⼤⼩的较⼩值。

- VS 中默认的值为 8

-Linux中gcc没有默认对⻬数,对⻬数就是成员⾃⾝的⼤⼩

3.结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的整数倍。

4.如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处,结构体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。

        好,如果你耐着性子看完了上面的一大堆,接下来就进入分析,如果你没看完,咱们接着进入分析。

先看第一个打印,第一个数据类型是char,先把他放到首位置上(红色),然后,第二个数据是int(绿色),我们应该算他的对齐数(对⻬数=编译器默认的⼀个对⻬数与该成员变量⼤⼩的较⼩值。)其中,vs默认是8,所以int在第4个位置上存下,然后下一个是char(蓝色),对齐数是1,8是他的整数倍,存到了第8个的位置上,那就会有人问了,这不就是8吗?这时就用到了第三点(结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的整数倍。),char的对齐数是1,int的是4,那么最后总大小应该为4的整数倍,就是12(0-11)。

接着我们看第二道题,同理,先是char,对齐数是1,接着又是char,对齐数是1,最后是int,对齐数是4,然后结构体的大小应该是max(1,1,4),所以最后是4的整数倍,而此时大小正好是8,满足条件。所以第一个是12,第二个是8.

这就给我们一个启示,以后为建立结构体方便节省空间,要把小的数据结构放在前面,大的放到后边,欸?真的是这样吗?看下边

struct s3{
	char a;
	double b;
	int c;
};
struct s4{
	double b;
	char a;
	int c;
};
int main() {
	printf("%u\n",sizeof(struct s3));
	printf("%u\n", sizeof(struct s4));
	return 0;
}

       

第一个char在前边,但是占用空间反而更大,看来没那么简单,我们需要具体情况具体分析

s3:

char先放进去,接着是double(double本身大小是八,编译器大小默认是8,取较小值是8),然后int,对齐数是4,恰好16是4的倍数,然后三个对齐数中最大值是8,所以结构体大小应该是8的整数倍,最后是24

s4较为简单,大家画图应该也能出来,就不讲了,

所以这就推翻了我们上面的结论,那应该是什么呢?我们应让占用小的数据结构尽量集中在一块

接下来最后一种情况,结构体嵌套:

struct s4{
	double b;
	char a;
	int c;
}A;
struct s3 {
	char a;
	struct s4 A;
	int c;
};
int main() {
	printf("%u\n",sizeof(struct s3));
	return 0;
}

首先s4占16个字节,接着看s3

char占一个,紧接着存了s4,s4中有三个元素,对齐数分别是8,1,4,依据第四条规则,我们取8,所以应存到第八个位置,接着24正好是4的倍数,所以int能够存,然后所有元素中最大倍数是8,分别是(1,8,4),所以最后大小是32.

到此我们的全部内容就讲完了,但不知大家是否有这样的疑问,c语言中的struct存在内存对齐的现象,那么c++类呢?两者如此像,是的,c++中也有内存对齐现象

那么内存对齐的目的是什么呢?答案就是以空间换时间

1. 平台原因(移植原因):
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2. 性能原因:
数据结构(尤其是栈)应该尽可能地在⾃然边界上对⻬。原因在于,为了访问未对⻬的内存,处理器需要作两次内存访问;⽽对⻬的内存访问仅需要⼀次访问。假设⼀个处理器总是从内存中取8个字节,则地址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对⻬成8的倍数,那么就可以⽤⼀个内存操作来读或者写值了。否则,我们可能需要执⾏两次内存访问,因为对象可能被分放在两个8字节内存块中。
总体来说:结构体的内存对⻬是拿空间来换取时间的做法。

大家中秋快乐哦,如果产生了那么一丢丢的帮助,还请点个赞哦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值