C++ 内存对齐详解加配图分析

C++内存对齐
因为cpu在存取指令的时候,以字节长为单位进行存取,32位机器默认字节长4字节,64位机器默认长8字节。cpu每次读取都从对齐字节的整数倍开始读取,而存放数据cpu以对齐字节的整数倍进行存放,这要求我们对struct或class内的数据排布提出了要求。

看这样一段代码

#include<iostream>
using namespace std;
struct A {
    char c;
    short s[3];
    char cs[3];
};
struct B {

    short s[3];
    char cs[3];
    char c;
};
struct C{
    char c;//8   
    double d;//16
    int i[2];//24

};
int main()
{
    A a;
    B b;
    C c;
    printf("%p %p %p %p   %d\n", &a,&a.c,a.s,a.cs,sizeof(A));
    //0079FEB0 0079FEB0 0079FEB2 0079FEB8   12
    //            0  ->  2   ->  8  -> 12

    printf("%p %p %p %p    %d\n", &b, &b.s, &b.cs, &b.c,sizeof(B));
    //0079FE9C 0079FE9C 0079FEA2 0079FEA5    10
    //            12    ->   16*1+2=18   -> 16*1+5=21   -> 21+1=22   

    printf("%p %p %p %p   %d\n", &c, &c.c, &c.d, &c.i, sizeof(C));
    //00F6F81C 00F6F81C 00F6F824 00F6F82C   24
    //            12   ->   16*1+4 = 20  -> 16*1+12=28  ->  28+8=36 
    return 0;
}

struct A的大小占比为12字节
在这里插入图片描述

而struct B的大小占10字节

在这里插入图片描述

而struct C的大小占8字节?(为啥一个char c需要8字节?==》因为内存对齐是按成员变量中sizeof最大值作为对齐条件)

在这里插入图片描述

内存对齐规律

  1. 对于结构体的各个成员,第一个成员位于偏移为0的位置,结构体第一个成员的偏移量(offset)为0,以后每个成员相对于结构体首地址的offset都是该成员大小与有效对齐值中较小那个的整数倍,如有需要编译器会在成员之间加上填充字节。

  2. 除了结构成员需要对齐,结构本身也需要对齐,结构的长度必须是编译器默认的对齐长度和成员中最长类型中最小的数据大小的倍数对齐。

我们再来看看如果struct中有包含sturct呢?

#include<iostream>
using namespace std;
struct A {
    char c;
    short s[3];
    char cs[3];
};
struct B {

    short s[3];
    char cs[3];
    char c;
};
struct C{
    A a;//12
    char c;//16   
    double d;//24
    int i[2];//32

};
struct D {
    B b;//10
    char c;//16 
    double d;//24
    int i[2];//32

};
int main()
{
    C c;   
    D d;
    printf("%p %p %p %p %p   %d\n", &c, &c.a ,&c.c, &c.d, &c.i, sizeof(C));
    //010FFEBC 010FFEBC 010FFEC8 010FFECC 010FFED4   32
    //            12 -> 16+8=24 -> 16+12=28  -> 16*2+4=36 ->  44 
    printf("%p %p %p %p %p   %d\n", &d, &d.b, &d.c, &d.d, &d.i, sizeof(D));
    // 010FFE94 010FFE94 010FFE9E 010FFEA4 010FFEAC   32
    //             4   ->     14 ->16+4=20->  16+12=28 -> 36
    //            
    return 0;
}

对于C
在这里插入图片描述

对于D

在这里插入图片描述

如果把A/B放在C/D的最下面呢?

#include<iostream>
using namespace std;
struct A {
    char c;
    short s[3];
    char cs[3];
};
struct B {

    short s[3];
    char cs[3];
    char c;
};
struct C{

    char c;//8   
    double d;//8
    int i[2];//8
    A a;//16
};
struct D {

    char c;//8 
    double d;//8
    int i[2];//8
    B b;//16
};
int main()
{
    C c;   
    D d;
    printf("%p %p %p %p %p   %d\n", &c ,&c.c, &c.d, &c.i, &c.a, sizeof(C));
    //0113FBFC 0113FBFC 0113FC04 0113FC0C 0113FC14   40
    //            12 -> 16+4=20 -> 16+12=28  -> 16*2+4=36 ->  36+16=52 
    printf("%p %p %p %p %p   %d\n", &d, &d.c, &d.d, &d.i, &d.b, sizeof(D));
    // 0113FBCC 0113FBCC 0113FBD4 0113FBDC 0113FBE4   40
    //             12->  16+4=20 ->16+12=28->16*2+4=36->36+16=52
    //            
    return 0;
}

对于C

在这里插入图片描述

对于D

在这里插入图片描述

所以无论如何它们都要按照8的整数倍进行对齐。

而最后的A/B则因为超过了8所以按16对齐。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值