C语言中,字节对齐,内存对齐的影响范围

概要

        众所周知,C语言中的结构体类型的成员,其中若是存在不同类型的变量,则会在编译器优化寻址的过程中,产生缝隙。本文将使用菜鸟教程的C语言在线工具,来进一步研究它的影响。

技术名词解释

        #pragma  pack() 这条指令主要用于指定字节对齐的方式

        括号内的数字必须要是 2 的小幂,否则不会有任何效果。通常我们填的数字都是1,它是2的0次方,其值可以为1,2,4,8,16。如果你指定的对齐字节数,超过了结构体中的最长的那个数据类型,那么它仍然是以最长的那个数据类型对齐的。它所指定的字节对齐是指不同数据类型之间的对齐方式。

        下图是指定字节对齐为2时,结构体所占用的内存大小,其余的值依次类推。

         

技术细节

        该在线工具中,是属于64位的,其中 char 是1个字节,short int 是2个字节,int  是4个字节的,float 是4个字节,double 是8个字节。

        但在8位单片机中,short int 和 int 的字节长度都是 2 个字节,不要混淆。

        前言结束,实验开始。

        还是老样子,printf 调试大法。 这里先提一个细节:就是 sizeof 是属于C的关键字,所以你可以不用加括号,打个空格也是可以使用的,它是用来求,在当前系统下的数据类型的大小。

        回到正题,按理论来说 char 型和 int 型加起来应该是 5 个字节。但是我们打印出来却是8个字节,那么重点来了,就让我们依次实验一下,编译器在优化寻址的过程中,造成的影响范围到底有多大!

        上面这个状态是理想中希望的,实际字节数和打印字节数一致。

惊不惊喜,意不意外?int变量类型的前一段空间和后一段空间都受到了影响,别急,还有更惊喜的呢。

       

        至此,我们已经不难看出,结构体内的成员变量的优化方式,是以最先遇到的最大的那个数据类型来对齐的,但是呢,假如它的前一段或者后一段有剩余没有使用的,那么更小的数据就会被放入这个缝隙,当这个缝隙填满之后,再开辟一个新的和最大数据类型大小一致的空间,无论你的最大类型的数据位置是在前,在后,还是在中间,都是以它来进行对齐。如果你不希望造成更多的空间浪费建议你将最大的数据类型定义时放在最前面,最小的放在最后面。当然,这个忠告仅对那些不能使用 #pragma  pack(1) 指令的编译器生效。

所以像如下这种结构体成员的定义的方式就会非常浪费空间,本来10个字节的数据却使用了24个字节的内存

struct st_aaa
{
  char a[1];
  double  b;
  char c[1];
};

        当你使用字符串复制函数 strncpy 数据的时候,就会因为这段空白内存而出现bug,更好的复制数据方式应该使用 memcpy 直接搬运内存。

小结

        当下,在keil里面。使用#pragma  pack(1)指令进行1字节对齐,编译32的可以,但是编译51,或者其他八位机,会报一个被忽略的行的警告,编译器不支持这种指令。

        user\main.c(110): warning C245: unknown #pragma, line ignored。

当下国产STC8的单片机性能越逐渐强大,远远超越传统8051,使用的人也很多,所以对于字节对齐的进一步研究还是有必要的,希望本文能帮助到诸君认识到该问题。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沉缘铭尘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值