C语言 结构体的大小和最小浪费空间

因为内存对齐的问题,各个数据类型放的位置不同就会导致结构体的大小不一样,那么到底
怎样计算一个结构体的大小呢?

(最近在计算机系统课上发现的这个问题,只好重新拿起C语言)

许多计算机系统对基本数据类型的合法地址做出了一些限制,要求某种类型对象的地址必须是某个值K( 通常是2 、4 或8 )的倍数。这种对齐限制简化了形成处理器和内存系统之间接口的硬件设计。

类型K
char1
short2
int,float4
long,double,char*8

我们可以发现这个K值是和数据类型有关的(等于)。而这个K值有影响到后面的内存对齐。

当我们创建一个结构体:

typedef struct STRU{
    char a;
    short b;
    double c;
    char d;
    float e;
    char f;
    long g;
    int h;
}S;

创建结构体后,在内存中的情况为:

第一个数据a为字符型大小为1K=2,偏移应该为1的倍数,则偏移=0(开始偏移为0);

第二个数据b短整型大小为2 , K=2,偏移应该为2的倍数,则偏移=2

第三个数据c双精度小数型大小为8 , K=8,偏移应该为8的倍数,则偏移=8

第四个数据d字符型大小为1 , K=1,偏移应该为1的倍数,则偏移=16

第五个数据e单精度小数型大小为4 , K=4,偏移应该为4的倍数,则偏移=20

第六个数据f字符型大小为1 , K=1,偏移应该为4的倍数,则偏移=24

第五个数据g长整型大小为4 , K=4,偏移应该为4的倍数,则偏移=28

第五个数据h整型大小为4 , K=4,偏移应该为4的倍数,则偏移=32

至此,内存上已经占用了36个空间,由于结构体的大小必须为结构体成员中最大成员大小(这个结构体中为8)的倍数,则这个时候分配的空间大小应该为40

我们也可以用程序来验证:

#include <stdio.h>
int main ()
{
    typedef struct STRU{
        char a;
        short b;
        double c;
        char d;
        float e;
        char f;
        long g;
        int h;
    }S;
    S A = {"a",2,3.1,"d",5.3,"f",777777777777,8};
    printf("a in 0x%x\n",&(A.a));
    printf("b in 0x%x\n",&(A.b));
    printf("c in 0x%x\n",&(A.c));
    printf("d in 0x%x\n",&(A.d));
    printf("e in 0x%x\n",&(A.e));
    printf("f in 0x%x\n",&(A.f));
    printf("g in 0x%x\n",&(A.g));
    printf("h in 0x%x\n",&(A.h));

    printf("Size=%d",sizeof(T));
   return 0;
}

输出结果:

a in 0x61fef8
b in 0x61fefa
c in 0x61ff00
d in 0x61ff08
e in 0x61ff0c
f in 0x61ff10
g in 0x61ff14
h in 0x61ff18

Size=40

为了更加直观的显示在内存的分布对齐情况可以查看下图(白色为浪费的空间,红色存放有数据):


)按照一些规律就可以很清楚的写出一个结构体的分布和对齐,下面是自己总结的一些简单的规律:

  • 在内存上数据的偏移量与K有关(偏移量为K的倍数)。
  • K的大小与数据类型有关 (数据类型大小=K,通常是2 、4 或8 )。
  • 结构体的大小必须为结构体成员中最大成员大小的倍数。

根据图我们就可以发现,浪费的空间比较大,我们可以在结构体中按照数据大小降序来有效的节约空间、

#include <stdio.h>
int main ()
{
    typedef struct STRU{
        double c;
        float e;
        long g;
        int h;
        short b;
        char a;
        char d;
        char f;
    }S;
    S A = {"a",2,3.1,"d",5.3,"f",77777777,8};
    printf("c in 0x%x\t%d\n",&(A.c),sizeof(A.c));
    printf("e in 0x%x\t%d\n",&(A.e),sizeof(A.e));
    printf("g in 0x%x\t%d\n",&(A.g),sizeof(A.g));
    printf("h in 0x%x\t%d\n",&(A.h),sizeof(A.h));
    printf("b in 0x%x\t%d\n",&(A.b),sizeof(A.b));
    printf("a in 0x%x\t%d\n",&(A.a),sizeof(A.a));
    printf("d in 0x%x\t%d\n",&(A.d),sizeof(A.d));
    printf("f in 0x%x\t%d\n",&(A.f),sizeof(A.f));

    printf("Size=%d",sizeof(T));
   return 0;
}

结果:

c in 0x61ff00   8
e in 0x61ff08   4
g in 0x61ff0c   4
h in 0x61ff10   4
b in 0x61ff14   2
a in 0x61ff16   1
d in 0x61ff17   1
f in 0x61ff18   1
Size=32