目录

一.结构体的成员在内存中的存储是连续的吗?

二.结构体内存对齐规则:(4个规则)

三.分析最开始的代码:

​编辑

3.1训练一:

3.2训练二:

3.3训练三:

3.4训练四:

四.为什么结构体不连续存储

五.修改编译器的默认对齐数

六.结构体传参

6.1传值:

6.2传址:

6.3访问结构体里的内容:


看云不止识天气

一.结构体的成员在内存中的存储是连续的吗?

先来看看下面代码:

#include<stdio.h>
struct stu
{
	char a;
	int b;
};
int main()
{
	printf("%zd\n", sizeof(struct stu));
	return 0;
}

如果直接连续存储,char 占用1个字节,int占用4个字节,结果打印5。

但是结果这的是如此吗?

所以结构体的数据不是连续储存的

二.结构体内存对齐规则:(4个规则)

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

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

每一个成员都有一个对齐数

---VS中的默认对齐数是8

---Linus中gcc没有默认对齐数,对齐数是成员自身的大小

用默认对其数和成员变量的大小进行比较,较小的就是对齐数。

例如:

int的对齐数大小是4字节,默认对齐数是8,所以较小的4。则int的对齐数4,int只能从结构体起始位置偏移量为4的整倍数开始存放(4,8,12)。

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

例如:如果结构题的最后一个成员存放完以后的结束偏移量是11,但是结构体里的最大对齐是4,那么结构体的总大小为12。

4. 如果嵌套了结构体的情况,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处,结构体总大小是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍。

三.分析最开始的代码:

***根据对齐规则1,结构体的第一个成员对齐到结构体起始位置偏移量为0的地址处,char类型占一个字节。

***此时偏移量来到1,下一步是要进行int。根据对齐规则2,int类型不能从偏移量为1(不是int对齐数的整倍数)的地方开始存放。所以int从偏移量为4的位置开始存放,大小是4个字节。

***此时偏移量来到8,根据对齐规则3,结构体的总大小必须要是最大成员偏移量的整倍数。根据上面可知,char的偏移量是1,int的偏移量是4。现在偏移量是8,8是4的整倍数,所以struct stu的总大小是8个字节。

3.1训练一:

#include<stdio.h>
struct stu
{
	char a;
	int b;
	char c;
};
int main()
{
	printf("%zd\n", sizeof(struct stu));
	return 0;
}

char a从0到1,int 从4到8,char c从8到9,结构体总大小要是最大结构体成员对齐数的整数倍。9不是4的倍数,所以总大小是12;

3.2训练二:

char c[3]相当与三个char;

3.3训练三:

1,double a ( 0~8);2,char b (8~9);3,int c (12~16)

3.4训练四:

对齐规则4: 如果嵌套了结构体的情况,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处,结构体总大小是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍。

#include<stdio.h>
struct stu1
{
	char a;
	int b;
};
struct stu2
{
	char a;
	struct stu1 s;
	int c;
};
int main()
{
	printf("%zd\n", sizeof(struct stu2));
	return 0;
}

***stu1的总大小是8;最大对齐数是4;

***分析stu2:

char a(0~1),struct stu1 s(4~12);int c(12~16);

struct的最大对齐数是4,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处,这里也就是对齐4;

四.为什么结构体不连续存储

1. 平台原因 (移植原因):

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

2. 性能原因:

数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要⼀次访问。假设一个处理器总是从内存中取8个字节,则地址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对齐成8的倍数,那么就可以用一个内存操作来读或者写值了。否则,我们可能需要执行两次内存访问,因为对象可能被分放在两个8字节内存块中。

*为了节省空间,我们可以尽可能把小类型(char)的放一起。

五.修改编译器的默认对齐数

#include<stdio.h>
#pragma pack(1)        //修改编译器默认对齐数为1;
struct stu
{
	char a;
	int b;
};
#pragma pack()         //取消默认对齐数为1;
int main()
{
	printf("%zd\n", sizeof(struct stu));
	return 0;
}

六.结构体传参

6.1传值:

str是s的临时拷贝,但是arr[100],形参会浪费大量空间。

6.2传址:

6.3访问结构体里的内容:

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐