结构体的长度计算

现在有以下语句:

struct _THUNDER{
       int iVersion;
       char cTag;
       char cAdv;
       int iUser;
       char cEnd;
}Thunder;
int sz = sizeof(Thunder);
`</pre>

则执行后,变量sz的值将得到
A 11
B 12
C 13
D 16

结构体大小确定的原则:
- 每个变量自己先对齐——找到自己的位置。
      自对齐的原则是:按照变量声明的顺序,每个变量都只能以它长度的整数倍的地址作为起始存储地址。比如:char = 1;short = 2;int = 4;那么他们分别以1 的倍数、2的倍数、4的倍数作为起始位置,中间填不满的就作为空。声明顺序为,int ,char ,char  int  char ,按自身对齐原则计算,他们的长度为13
  • 再取最大长度的变量的长度作为有效读取宽度,要使得总大小为有效读取宽度整数倍
    因此,有效读取宽度为 4, 自对齐的结果是13,不是4的整数倍,因此将其补满16.故而结果是16.</p>
  • 格式一:

    `struct tagPhone
    {
         char   A;
         int    B;
         short  C;
    }Phone;
    `
  • 格式二:

    `struct tagPhone
    {
         char   A;
         short  C;
         int    B;
    }Phone2;
    `

    格式三:

    `struct tagPhone3
    {

     char   A;
     char   B[2];
     char   C[4];
    

    }Phone3;

我们都知道,char类型占用1个字节,int型占用4个字节,short类型占用2个字节,long占用8个,double占用8个;
那么我们可能会犯一个错误就是直接1+4+2=7,该结构体占用7个字节。这是错的。
以下我们简单分析下:

计算结构体大小时需要考虑其内存布局,结构体在内存中存放是按单元存放的,每个单元多大取决于结构体中最大基本类型的大小。

  • 对格式一:

    以int型占用4个来作为倍数,因为A占用一个字节后,B放不下,所以开辟新的单元,然后开辟新的单元放C,所以格式一占用的字节数为:3*4=12;
  • 同理对于格式二,

    A后面还有三个字节,足够C存放,所以C根着A后面存放,然后开辟新单元存放B数据。所以格式二占用的内存字节为2*4=8.

  • 对于格式三:

    上面结构计算大小,sizeof(Phone3) = 1 + 2 + 4 = 7, 其大小为结构体中个字段大小之和,这也是最节省空间的一种写法。

总结:

  • 第一种写法,空间浪费严重,sizeof 计算大小与预期不一致,但是保持了每个字段的数据类型。这也是最常见的漫不经心的写法,一般人很容易这样写;

  • 第三种写法,最节省空间的写法,也是使用 sizeof 求大小与预期一样的写法,但是全部使用字节类型,丢失了字段本生的数据类型,不方便使用;

  • 第二种写法,介于第一种和第三种写法之间,其空间上比较紧凑,同时又保持了结构体中字段的数据类型。