C语言中结构体所占内存空间

引例

先看这样一段程序。

    // tStructSize.c
    #include<stdio.h>
    struct perInfo1{
      int num; // 4 bytes
      char name[10]; // 10 bytes
      double account; // 8 bytes
    };
    struct perInfo2{
      char name[10]; // 10 bytes
      double account; // 8 bytes
      int num; // 4 bytes
    };
    int main()
    {
      struct perInfo1 Tony1 = {1,"Tony",3.14159};
      int structSize1 = sizeof(struct perInfo1);
    
      struct perInfo2 Tony2 = {"Tony",3.14159,1};
      int structSize2 = sizeof(struct perInfo2);
    
      printf("Size : { int, char[10], double } = %d\n",structSize1);
      printf("Size : { char[10], double, int } = %d\n",structSize2);
      return 0;
    }

我们用sizeof函数查看一下结构体的大小。拍脑瓜一想 4+10+8=22,然而编译执行后输出却并非如此。那为什么是24和32呢?定义变量顺序的不同还会影响结构体的内存空间大小吗?
在这里插入图片描述

结构体的内存空间分配

先给出一个类似公式的结构体大小计算方法:

结构体大小 = 末尾成员偏移量+末尾成员大小+末尾填充字节数

然后我们解释以下perInfo1的分配内存过程,以便理解上面的“公式”,当我们定义一个这样的结构体时,操作系统会为该结构体分配一段连续的存储单元。

    struct perInfo1{
      int num; // 4 bytes
      char name[10]; // 10 bytes
      double account; // 8 bytes
    };
    struct perInfo1 Tony1 = {1,"Tony",3.14159};
  1. 首先为成员变量num分配 4 个字节的内存,它是该结构体的第一个成员变量,所以num的地址就是perInfo结构体的首地址,无偏移。如图(假设这是内存中的地址空间);
    在这里插入图片描述

Tips 偏移量:这里可以简单理解为结构体内成员变量的地址距离结构体首地址的相地指数的大小。


  1. 然后开始考虑为name分配空间,name是由10个char型组成,可以认为是连续定义10个char变量。由于结构体在做字节对齐的时候有这样一个规则:每个成员相对于结构体首地址的偏移量必须是当前成员所占字节数的整数倍,如果不是,操作系统就会自动在前一个成员变量后自动填充补齐。
    当前偏移量是 4 ,是 1 (char类型)变量的的整数倍,不用填充,由如图分配。
    在这里插入图片描述

  2. account分配空间:double型变量占用 8 个字节,而当前可分配地址的偏移量为 14 ,不是 8 的整数倍,需要做字节填充。
    在这里插入图片描述

    填充后我们把偏移量为16的地址空间分配给account成员变量。这样就完成了结构体 perInfo1 的内存空间分配(perInfo2还存在另一个问题),大小为 24 字节。

  3. 在结构体定义完成前,还会进行如下判断:
    当前结构体的总大小是否为其最宽成员所占内存大小的整数倍,如果不是的话还要再将其填充成为整数倍。这也就是perInfo2的大小是 32 而不是 30 的原因了。


Tips perInfo2中当前结构体占位 30 字节,其最宽成员为 double 类型的 account 成员,占有 8 字节,因此要填充成 8 的整数倍 32 。


在这里插入图片描述

20210429更正图片如下。
在这里插入图片描述

  1. 我们也可以通过查看存储变量的地址来验证上面所述。

  printf("Size : {int,char[10],double} = %d\n",structSize1);
  printf("-----{%d, %d, %d }\n",&(Tony1.num),&(Tony1.name),&(Tony1.account));
  printf("Size : {char[10],double,int} = %d\n",structSize2);
  printf("-----{%d, %d, %d }\n",&(Tony2.name),&(Tony2.account),&(Tony2.num));

在这里插入图片描述

.
.
.
.
.
.
桃花仙人种桃树,又摘桃花换酒钱_

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值