2024年最全结构体对齐为什么那么重要?_c语言结构体位置重要吗(1),2024年最新记得把每一次面试当做经验积累

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

这里先解释下“模数”的概念:

每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。

接着看网上流传一个表:

本文的的例子我用的是MinGW32的GCC来测试,你猜符合上表的哪一项?

别急,再看一个例子:

    typedef struct     {        int e_int;        double e_double;    }S11;    S11 s11;    STRUCT_E_ADDR_OFFSET(s11, e_int);    STRUCT_E_ADDR_OFFSET(s11, e_double);

结果是:

  s11 size = 16        s11.e_int addr: 0028FF18, offset:  0  s11 size = 16     s11.e_double addr: 0028FF20, offset:  8

很明显,上表没有一项完全对应得上的。简单汇总以下我测试的结果:

**所以再强调一下:因为环境的差异,**在你参考使用之前,请自行测试一下。

其实,这个模数是可以改变的,可以用预编译命令**#pragma pack(n)**,n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。

例如:

#pragma pack(1)typedef struct {    char e_char;    long double e_ld;}S14;#pragma pack()

想知道结构图元素内存如何对齐,其实非常简单。
其实,你只需知道当前你使用的这个系统的基本类型的sizeof是多少,然后根据这个大小做对齐排布。例如,本文一开始的例子:

    typedef struct     {        int e_int;        char e_char1;        char e_char2;    }S2;
    typedef struct     {        char e_char1;        int e_int;        char e_char2;    }S3;    S2 s2;    S3 s3;

32位系统中,它们内存是这么对齐的:

简单解释下:

S2中的元素e_int是按4字节对齐的,其地址位4整数倍,而e_char1和e_char2就按1字节对齐,紧跟其后面就可以了;

而S3中的元素e_char1是按1字节对齐的,放在最前面,而e_int是按4字节对齐的,其地址位4整数倍,所以,只能找到个+4的位置,紧接着e_char2就按1字节对齐,跟其后面就可以了。

那么sizeof(s2)和sizeof(s3)各是多少怎么算?

也很简单,例如这个32位系统,为了提高执行效率,编译器会让数据访问以4字节为单位的,所以S2里有2个字节留空,即sizeof(s2)=8,而sizeof(s3)=12。

是不是很简单呢!

接着,来个复杂一点的:

    typedef struct     {        char e_char1;        short e_short;        char e_char2;        int e_int;        char e_char3;    }S4;    S4 s4;

其内存分布如下:

按上面的方法,也不难理解。e_int是不能从+5位置开始的,因为+5不是int的对齐位置,用int去访问+5位置是效率很低或者有问题的,所以它只能从+8位置开始。
再复杂一点的呢?来看看union和struct结合的例子:

    typedef struct    {        int e_int1;         union        {            char ue_chars[9];             int ue_int;        }u;        double e_double;         int e_int2;     }SU2;    SU2 su2;  

得到:

为什么这样呢?
你这样想,要时刻想着CPU访问数据的效率,如果union里的元素类型不一样,那就以最大长度的那个类型对齐了。另外,还有结构体套着结构体的情况了:

typedef struct     {        int e_int;        char e_char;    }S1;   typedef struct     {        S1 e_s;        char e_char;    }SS1;
    typedef struct     {        short e_short;        char e_char;    }S6;
    typedef struct     {        S6 e_s;        char e_char;    }SS2;   

得出结果:

得出结论:结构体内的结构体,结构体内的元素并不会和结构体外的元素合并占一个对齐单元。

只要技术上面的对齐方法,这些都不难理解。
如果你非要一些规则的话,我总结成这样:

首先,不推荐记忆这些条条框框的文字,以下内容仅供参考:

  1. **结构体的内存大小,并非其内部元素大小之和;

**
2. 结构体变量的起始地址,可以被最大元素基本类型大小或者模数整除;
3. 结构体的内存对齐,按照其内部最大元素基本类型或者模数大小对齐;
4. 模数在不同平台值不一样,也可通过#pragma pack(n)方式去改变;
5. 如果空间地址允许,结构体内部元素会拼凑一起放在同一个对齐空间;
6. 结构体内有结构体变量元素,其结构体并非展开后再对齐;
7. union和bitfield变量也遵循结构体内存对齐原则。

其实,这些都没必要去记,多思考多理解就OK了。唯一需要记得是某系统平台下的基本类型的sizeof大小,然后按照对齐原则来就可以了,就是时刻想着CPU要提升数据访问效率的。

END

*版权归原作者所有,如有侵权,请联系删除。*
外资芯片大厂又裁员:研发一个不留!
国产FPGA开发板上手体验:不足百元,冲击高端

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

阶课程,涵盖了95%以上C C++开发知识点,真正体系化!**

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值