结构体在内存中的存储
三.分析最开始的代码:***根据对齐规则1,结构体的第一个成员对齐到结构体起始位置偏移量为0的地址处,char类型占一个字节。***此时偏移量来到1,下一步是要进行int。根据对齐规则2,int类型不能从偏移量为1(不是int对齐数的整倍数)的地方开始存放。所以int从偏移量为4的位置开始存放,大小是4个字节。***此时偏移量来到8,根据对齐规则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访问结构体里的内容:
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)