结构体内存对齐——你想要知道的都在这里

结构体内存对齐——你需要知道的都在这里

提出问题

  • 首先,要申明的是,我们声明的结构体类型或者类自身是没有空间的,这只是一种数据类型的集合,是一种数据组织形式
  • 而当创建了结构体对象(实例化),才有真正的空间存在
  • 如果看到使用sizeof(struct A),其实代表的是这个结构体/类实例化以后的大小
  • 看下面这段代码,你能计算得到正确的输出吗?
struct A{
    char c;
    int a;
};

class B{
    char c;
    int a;
};

int main(){
   cout<<sizeof(struct A)<<endl;	//输出8
   cout<<sizeof(class B)<<endl;	//输出8
   return 0;
}
  • 看上面这个例子,很多人可能会认为答案是1+4=5Bytes,其实结果是8,这就是我们今天要学习的内容,请接着往下看

为什么需要内存对齐?

  • 这和取内存的操作有关,一般存取内存是按组来存取,如果需要取的数据跨越了两组,那么取数据时效率就会变低
  • 所以结构体对齐是为了更快的内存读取,本质上也是用空间换时间的手段之一

结构体(类)大小的计算

  • 拿到一个结构体,结构体里或许会有数组,有整型(int),浮点型(float、double),字符型(char)等等,甚至有可能有另一个结构体
  • 拿到一个类,类内会有成员变量与成员函数,或者其他类,那么要记住的是:只有非静态成员变量才属于这个实例的空间上,虚函数会存在指向虚函数表的指针,其余都不在这个实例化的对象上

第一个概念:最小对齐单位

  1. 在windows环境下,一般系统默认对齐单位为8,而在linux系统里是区分32位或64位系统的,32位默认对齐单位为4,64位系统默认为8
  2. 你也可以通过自定义来设置对齐单位,通过#pragma pack(n)来设置
  3. 取决于结构体中最大的那个数据类型所占用的大小,一般也就是double的8位了
  • 在根据上述的三条得出对齐单位后,选出最小的一个就是这个结构体的最小对齐单位。
  • 在清楚最小对齐单位后,你需要知道的事情是,这整个结构体,最后的总大小,一定是这个最小对齐单位的整数倍,例如最小对齐单位为8,则整个结构体的空间就是8的倍数。

第二个概念:结构体中成员的摆放规则

  1. 现在我们要将结构体中的成员放入内存空间,肯定不是挨着放或者随便放那么简单,而是要遵循结构体内存对齐的原则
  2. 当你遇到一个成员时,你应该首先考虑其类型所占的字节数,例如char类型就考虑占1个字节,int类型就考虑占4个字节,然后把这个成员变量填在其类型所占字节数整数倍的地方;假如这个成员是另一个结构体:例如结构体B内嵌套着1个结构体A,那么这个结构体A在结构体B的空间中应该从哪里开始摆呢?答案是:从这个A结构体中最大占用字节数的整数倍开始摆!!例如:结构体A中有char、int、double,则A结构体在B中就要从double(8字节)的整数倍开始摆。
  3. 最后,之前说过整个结构体大小一定是最小对齐单位的整数倍,所以末尾不足要补齐

接下来就是实践环节:

我们就举一两个稍微复杂的例子吧

struct A
{
    char c1;	
    int n;	
    char c2;	
};

struct B	
{
    char c1;	
    A a;
    double b;
    char c2;
};

请问B结构体所占大小为多少?答案是32哦!

详细解析

struct A	//最小对齐单位为4,因为int类型占4Bytes
{
    char c1;	//本来是1,但因为下面的int要从4的整数倍开始摆,所以+3B的冗余
    int n;	//正常为4
    char c2;	//本来是1,但因为最终结构体大小需要时最小对齐单位的整数倍,故升级为4,有3B的冗余
};	//所以答案就是4+4+4=12

struct B	//最小对齐单位是8
{
    char c1;	//本来占一个字节,但下面的a要从a的最小对齐单位4开始,所以+3B冗余                4
    A a;	//上面已经算出来了,占12字节                   12
    double b;	//刚好从double也就是8的整数倍开始,所以不用挪,就是8Bytes            8
    char c2;	//一个字节,但为了整体结构体大小要是最小对齐单位的整数倍,故+7Bytes冗余         8
};	//所以答案就是4+12+8+8=32
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值