C语言详细分析结构体的内存对齐规则
作者:Hero 2021
结构体的内存对齐是一个特别热门的知识点!
引例
#include<iostream> using namespace std; struct S { char c; // 1 int a; // 4 char d; // 1 }; int main() { struct S s = { 'a',2,'y'}; cout << sizeof(struct S) << endl;// 12 cout << sizeof(s) << endl; // 12 return 0; }
结构体内存对齐规则
1. 结构体的第一个变量,永远放在结构体起始位置偏移量为0的地方。
2. 结构体成员从第二个成员开始,剩下的成员总是放在偏移量为一个对齐数的整数倍处。 对齐数=编译器默认的对齐数与变量自身大小的较小值(VS的默认对齐数是8,Linux没有默认对齐数)
3. 结构体的总大小,必须是结构体各个成员中最大对齐数的整数倍
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数( 含嵌套结构体的对齐数)的整数倍。
满足第一点:
满足第二点:
满足第三步:
为了满足第三点,我们要内存对齐,结构体的总大小必须是4的倍数,现在只有12能够满足要求了。
但是我们存在着一些空间的浪费啊!
那么为什么要有内存对齐呢
大部分的参考资料都是如是说的:
平台原因(移植原因):
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
性能原因:
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
例如:某些场景下一次只能读取4byte空间:对比对齐和不对齐,可能读取数据就可能出错。
总体来说:
结构体的内存对齐是拿空间来换取时间的做法。
如何优化
那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到呢? 那就是让占用空间小的成员尽量集中在一起。
//例如: struct S1 { char c1; int i; char c2; }; struct S2 { char c1; char c2; int i; };
S1和S2类型的成员一模一样,但是S1和S2所占空间的大小有了一些区别。
修改默认对齐数
用#pragma
修改默认对齐数
#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; }
结论:
结构在对齐方式不合适的时候,我么可以自己更改默认对齐数。
到此这篇关于C语言详细分析结构体的内存对齐规则的文章就介绍到这了,更多相关C语言内存对齐内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!