理解内存字节对齐(多图)

前言:

听到这个内存对齐 是不是感觉很难,很不好理解,但是面试官还喜欢考
其实非常好理解,看完这篇文章你肯定就明白了

先来看两个结构体
在这里插入图片描述
32位编译器下
int 4字节
double 8字节
short 2字节
这没问题吧

那么结构体sizeof(A) 是不是 4+8+2 = 14
结构体B也是 14 呢?

在这里插入图片描述

结果是不是和我们想的不一样

内存对齐的规则

  • 规则一 : struct 或者 union 的第一个数据成员要从偏移量offset 为0的位置开始,后面的其他成员的起始的位置要从该类型的字节大小的整数倍开始,比如int 为4字节 那么后面的int 的起始位置要从4的倍数开始.

    咱们来理解一下这一条 拿上面的A来举例
    A的第一个成员是int,从0开始 占4个字节,如下图

    在这里插入图片描述
    第二个成员是double ,占8字节,所以他的起始位置要从8的倍数开始,目前才用到位置3 所以最近的就是8
    在这里插入图片描述
    第三个成员是short,占两个字节,起始位置从2开始 目前已经用到15了 所以起始位置是16

在这里插入图片描述

这个内存排布图出来以后 ,你说那不应该是占用 0-17 共计 18个字节吗
继续看规则二

  • 规则二 : 结构体的总大小,sizeof的大小 必须是内部最大的成员的整数倍 ,不足的补齐

ok 最大的是b 8字节 ,那么a和c 都补齐吧 一共是 3*8 = 24 字节

看到这里上面的 sizeof(A) 为什么是24 理解了吧

问题又来了 如果 结构体中的成员是结构体怎么办?

在这里插入图片描述

这个 sizeof( c ) 是多少呢?

在这里插入图片描述

是 40

  • 规则三 :结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.)选择结构体中最大的存储

画一下图
在这里插入图片描述

前面两个 a 和 b 的我们应该懂 , 根据规则三 结构体中的结构体的起始位置是结构体中最大的整数倍 这里最大的是double 8 所以起始位置是 16 ,根据规则二 结构体的总大小根据 最大的填充 也就是 3个 8

所以这里是 0-39 共计40

如果看到这里上面都理解了 恭喜你基本的内存对齐就明白了

三条规则:

  • 规则二 : 结构体的总大小,sizeof的大小 必须是内部最大的成员的整数倍 ,不足的补齐
  • 规则二 : 结构体的总大小,sizeof的大小 必须是内部最大的成员的整数倍 ,不足的补齐
  • 规则三 :结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.)选择结构体中最大的存储

再讲讲#pragma pack().

在代码前加一句#pragma pack(1),你会很高兴的发现,上面的代码输出为

sizeof( A ) = 4+8+2 = 14

这不是理想中的没有内存对齐的世界吗.没错,#pragma pack(1),告诉编译器,所有的对齐都按照1的整数倍对齐,换句话说就是没有对齐规则.

C语言和C++中空类和空结构体的大小

在C++中规定了空结构体和空类的内存所占大小为1字节,因为c++中规定,任何不同的对象不能拥有相同的内存地址。
而在C语言中,空的结构体在内存中所占大小为0。(gcc中测试为0,其他编译器不一定)

为什么要内存对齐?

1.平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2.性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

参考 https://blog.csdn.net/hairetz/article/details/4084088

如果您看了本文感觉不错,请给点个赞或者关注支持一下 谢谢

发布了171 篇原创文章 · 获赞 386 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/weixin_42837024/article/details/102800382