C语言 结构体和位段(三)内存对齐现象

关于结构体所占空间大小怎么计算呢
这时候我们引入一个名词“内存对齐”
先来看一组现象:

struct S
{
    char name[20];
    int score;
    int age;
    double weight;
};

#include<stdio.h>
int main()
{
    printf("%d\n",sizeof(struct S));
    return 0;
}


结果:

40
Program ended with exit code: 0

咦?不应该是20+4+4+8 = 36吗

其实在结构体里存在内存对齐现象:
我们知道,不同类型占用字节数不一样,比如int-4,char-1,short-2等等,那么在我们系统里还有一个数叫做默认对齐值,这个值干嘛用的?是用来和不同类型变量比较的。

比较干什么?
他们比较,较小的数的倍数来做这个特定类型的偏移量。

什么是偏移量?
我们定这个结构体最开始储存数据的偏移量为0,并依次向下顺延,那么char型数组占20个字节,就占用了偏移量为0~19的位置,下一个变量储存的时候,起始位置偏移量必须在20及其以后(一个偏移量其实对应一个字节)

比如说,VS环境的默认对齐值是8个字节,也就是说,我int型4比8小,那我int就一定存储在4的倍数的偏移量上,那么char型数组占完19偏移量以后,我int型数据score一定要放在19后面,且为4的偏移量的位置上,也就是20,以此类推,age数据放在24上,double数据要放在8(8与8相比的最小值)的倍数上,也就是从32开始放占用偏移量32~39(也就是8个字节,大小和double类型变量一样)

后面还有结构体大小运算的举例

最终计算结构体大小,不只是0~39 共40个字节这么简单,还要以这里面最大的数据单位(double-8)为基准,找他的倍数

比如我最后一个数据储存到偏移量指向35就截止了,但因为我结构体里面最大的数据类型是double-8,所以我整个结构体要以8的倍数结尾,也就是最终指向40,最终(这段的例子)结构体大小就是40个字节

所以我们在进行创建结构体的时候,要尽量减小大小,就要尽量把占用空间小的变量放在一起,比如:

struct S
{
    char a;
    char b;
    int c;
    double d;
}s1;
printf("%d\n",sizeof(s1));

结果为16;
因为a指向偏移量0,占用0~1字节
b指向偏移量1,占用1~2字节
c指向偏移量2,但c为int类型,不能从偏移量为2的地方开始,需要从4和默认对齐数(一般为8)的较小值的倍数开始,即向后找,找到偏移量为4的位置,占用4~7字节
d则是相同的道理,取8和8的较小值:8,从8的倍数(8)开始,占用8个字节,即占用8~15字节

最终结构体的大小还不是0~15 共16字节这么简单,还要比较这个数(16)是不是结构体成员里面最大的变量占的空间的整数倍,一比,嗯,16确实是最大的double的整数倍,所以结果是16

而如果占用空间小的变量不放在一起呢?
给出了这样一个例子:

struct D
{
    char a;
    int b;
    char c;
    double d;
}s2;
printf("%d\n",sizeof(s2));

结果为24,方法如上分析

大家可以发现,明明相同类型的结构体(里面成员类型相同),大小差了这么多,是不是感到了这样节省内存的必要性!

上面提到了默认对齐数,指编译环境的默认对齐数(ps.VS环境是8),那我们可以手动修改这个数吗?

答:是可以的

方法:

#pragma pack(8)

类似于define的使用方法,语句后面不用加分号,整条语句放在函数体外面,括号里的数字就是我们设置的默认对齐数,一般方便起见,设置为2,4,8这样的数

设置完怎么消除,回复成默认的?
只要在结构体定义完以后

#pragma pack()

就可以了

整体效果像这样:

#include<stdio.h>
#pragma pack(8)
struct S
{
    char a;
    int b;
    double c;
};
#pragma pack()
int main()
{
    struct S s1;
    return 0;
}

不需要额外的头文件

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值