结构体内存对齐【收获满满】

吃得慢,吃的饱,易消化。

文章目录

    • 1:结构体内存对齐定义
    • 2:结构体内存对齐规则
      • 2.1:对齐规则1
      • 2.2:对齐规则2
      • 2.3:对齐规则3
      • 2.4:对齐规则4
    • 3:结构体内存对齐的意义
    • 4:结构体内存对齐的应用

1:结构体内存对齐定义

struct STU
{char name;
int age;
};
int main()
{printf("%d",sizeof(struct STU);
return 0;
}

初学结构体的人会认为,结构体类型的大小是其中各变量的大小之和,其实非也,下面是这段代码的运行结果。
在这里插入图片描述
char类型变量大小为1,int类型变量大小为4,所以结果应该为5,然而为8,这其中应该是计算机发生了什么过程。
如此引出我们本文的关键词结构体内存对齐。

2:结构体内存对齐规则

1. 第一个成员在与结构体变量偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的值为8
3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

接下来我们逐语句详解。

2.1:对齐规则1

结构体内存对齐【收获满满】_第1张图片

  1. 第一个成员在与结构体变量偏移量为0的地址处。

从上图最上面的横线看,那是结构体内存中的起始位置,也就是偏移量为0的地址,偏移量就是结构体内存中变量相对于起始位置偏移的大小。

根据规则1,结构体中第一个成员要自动对齐到偏移量为0的位置,所以我们把第一个成员name 放到0的位置,而name的大小为1个字节,所以从0偏移量转到1偏移量。也就是如下图所示
结构体内存对齐【收获满满】_第2张图片

2.2:对齐规则2

2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的值为8

对齐数也就是2.1中所说的偏移量。
char name,name的大小为1,而默认对齐数是8->对齐数=1;
int age,age的大小4,而默认对齐数是8->对齐数=4;

2.1我们已经把name存储进去,而int的对齐数要求是4的倍数,那么可以看下图

结构体内存对齐【收获满满】_第3张图片

偏移量为2和3的地方都不满足age的偏移量,那么age只能在4的倍数也就是偏移量为4后开始存储,而age的大小为4,所以占用4个字节后,偏移量达到了8。

2.3:对齐规则3

  1. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。

上面我们已经把name和age存储到内存中,最后一步就是计算结构体总体的大小,成员的对齐数分别为1和4,那么总大小为最大对齐数4的整数倍。
之前已经计算到偏移量为8的位置,也就是8个字节,8是4的倍数,那么总大小就为8。

2.4:对齐规则4

结构体中有时候会发生嵌套使用,而这个时候,对齐规则其实与上面是类似的。

struct stu
{
	char x;
	double y;
};
struct STU
{
	char name;
	struct stu;
	int age;
};
int main()
{
	printf("%d", sizeof(struct STU));
	return 0;
}

打印结果是32
1:我们先计算stu的内存大小,
1.1:stu里面的第一个成员类型为char,从0偏移量开始占用1个字节
stu里面的第二个成员类型为double,需要从8的倍数的偏移量开始,也就是从8开始占用8个字节,结果到了16,,16位8的倍数,所以stu的内存大小为16。
2:我们接着计算STU的大小
2.1:第一个成员类型为char,从0偏移量开始,占用1个字节,到了1偏移量,第二个成员为stu,根据对齐规则4,stu需要从他内部最大偏移量的整数倍的地址开始,他内部最大偏移量为8,所以STU需要从8开始偏移,他的内存大小为16,占用后变成24偏移量,最后的成员类型是int,24是4的倍数,直接开始占用int的偏移量4个字节,到了28。

而根据规则4,嵌套的结构体最后总大小需要是内部所有成员中最大偏移量的整数倍,也就是8个的整数倍,28下一个是8的整数倍的数字为32,所以最终打印32。
所以最终结果32,与运行结果一致。

3:结构体内存对齐的意义

因为我们知道char int double等数据类型的字节是1 4 8等等,如果说一个数据的存储地址在2这个位置,而他的类型为int,应该存储的地址在4的倍数上,所以计算机就需要进行2步操作,一步先到2上找到这个地址,第二步将这个数字送入4的倍数对应的位置上。这样一个例子如果扩大,一个数据查找需要10分钟,结构体内存如果没有对齐,那么就需要20分钟的时间,差异十分之大。

总结一下:结构体的内存对齐是拿空间来换取时间的做法。

4:结构体内存对齐的应用

根据上面的几个例子,我们可以发现如果将不同大小的成员摆放在不同的次序,该结构体的内存大小是不同的。所以我们给出以下参考方法。
在编写结构体的时候,尽可能的把数据大小小的数据放在前面,这样浪费的空间会更少,计算机性能会得到优化。

这个结论不妨大家多写几个代码试一下,这里便不再往下论述。
本篇博客到此结束,谢谢各位的来访。

你可能感兴趣的:(c#)