NO1
#include<stdio.h> #include<stddef.h> struct S1 { char c1;//1 int i;//4 char c2;//1 };//6 int main() { printf("%d\n", offsetof(struct S1, c1)); printf("%d\n", offsetof(struct S1, i)); printf("%d\n", offsetof(struct S1, c2)); return 0; }
我们发现有部分空间是被浪费了的??那S2也是这样吗?我们来看看
NO2
#include<stdio.h> #include<stddef.h> struct S2 { char c1;//1 char c2;//1 int i;//4 };//6 int main() { printf("%d\n", offsetof(struct S2,c1)); printf("%d\n", offsetof(struct S2,c2)); printf("%d\n", offsetof(struct S2, i)); return 0; }
NO3
除了上面的问题我们还有一个嵌套结构体大小的问题哟!🆗🆗
#include<stdio.h> #include<stddef.h> struct S3 { double d; char c; int i; }; struct S4 { char c1; struct S3 s3; double d; }; int main() { printf("%d\n", sizeof(struct S4)); return 0; }
关于数据在内存中的存储,偏移量有什么存储规则吗?当然,对齐规则。
内存对齐-结构体类型内存中存储
对齐规则也就是结构体在内存中如何存储
考虑如何计算?那我们首先要掌握结构体的对齐规则:
- 第一个成员在与结构体变量偏移量为0的地址处。
- 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
- 结构体总大小为最大对齐数(每个成员变量的对齐数 比较之后 最大的)的整数倍。
- 如果嵌套了结构体的情况,嵌套的结构体 对齐到 自己的成员中对齐数 最大对齐数 的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
- 对齐数 = 编译器默认的 一个对齐数 与 该成员本省的大小 比较之后的 较小值。
- VS中默认值为8
- Linux中gcc没有默认对齐数,对齐数就是成员自身的大小
NO1
#include<stdio.h> #include<stddef.h> struct S1 { char c1;//1 int i;//4 char c2;//1 };//6 int main() { printf("%d\n", offsetof(struct S1, c1)); printf("%d\n", offsetof(struct S1, i)); printf("%d\n", offsetof(struct S1, c2)); return 0; }
NO2
#include<stdio.h> #include<stddef.h> struct S2 { char c1;//1 char c2;//1 int i;//4 };//6 int main() { printf("%d\n", offsetof(struct S2,c1)); printf("%d\n", offsetof(struct S2,c2)); printf("%d\n", offsetof(struct S2, i)); return 0; }
NO3
#include<stdio.h> #include<stddef.h> struct S3 { double d; char c; int i; }; struct S4 { char c1; struct S3 s3; double d; }; int main() { printf("%d\n", sizeof(struct S4)); return 0; }
为什么要对齐
#include<stdio.h> struct S { char a; int i; };
参考大部分资料:
- 平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
- 性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
- 总体来说:结构体的内存对齐是拿空间来换取时间的做法
优化结构体成员顺序
那在设计结构体的时候,我们既要对齐,又要节省空间,如何做好:
//例如: struct S1 { char c1;//1 int i;//1 char c2;//4 };//8 struct S2 { char c1;//1 char c2;//4 int i;//1 };//12
S1和S2类型的成员一模一样,但是S1和S2所占空间的大小有了一些区别。
修改默认对齐数
结构在对齐方式不合适的时候,我们可以自己更改默认对齐数。一般设置默认对齐数:2的次方。
#include <stdio.h> #pragma pack(8)//设置默认对齐数为8 struct S1 { char c1; int i; char c2; }; #pragma pack()//取消设置的默认对齐数,还原为默认 #pragma pack(1)//设置默认对齐数为1 struct S2 { char c1; int i; char c2; }; #pragma pack()//取消设置的默认对齐数,还原为默认 int main() { //输出的结果是什么? printf("%d\n", sizeof(struct S1)); printf("%d\n", sizeof(struct S2)); return 0; }
大家自己动一动手画一画图,思考答案!
百度笔试题
写一个宏,计算结构体中某变量相对于首地址的偏移,并给出说明
考察: offsetof 宏的实现
注:这里还没学习宏,后面博文讲解。
✔✔✔✔✔最后,感谢大家的阅读,若有错误和不足,欢迎指正!
下篇博文我们继续自定义类型。
代码------→【gitee:唐棣棣 (TSQXG) - Gitee.com】
联系------→【邮箱:2784139418@qq.com】