你会计算 C 语言中的结构体的大小吗?


计算 sizeof(struct),很多初学者都会在这里栽跟头!

C语言中的结构体为我们提供了集中数据的机制,使用结构体可以将相关的数据存放在一起,组成一个有机整体,方便使用。下面是一个结构体示例:

struct tagPhone
{
     char   A;
     int    B;
     short  C;
}Phone;

结构体看似简单,但也要注意的地方,否则你很可能它会在未来某个时候让你发狂! Believe me~

就拿上面的结构体 Phone 来说,它在内存中占用多少字节?

当然是 7个字节啦,怎么算的呢? sizeof(char) + sizeof(int) + sizeof(short) = 1 + 4 + 2  = 7 ,恩,算术过程很正确。恭喜你,答错了!!!


正确的计算方法

不是你的算术过程错了,而是编译器不是这样计算的。

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

如,char 是 1 字节,short 是 2  字节, int 是 4 字节(之前这里笔误了,谢谢网友提醒~), long 是 4 字节 , long long 是 8 字节(具体情况视编译器而定,不过一般是这样)

比如上面的结构体 Phone 其存储单元就是 4 字节(因为最大的类型为int),其存储过程是这样的:

            
     图 1  结构体 Phone 的内存布局

先存储 char 类型的字段A,占 1 个字节;
再存储 int 类型的字段B,占 4 个字节,但是存储单元中只剩下3个字节空间,而编译器是不会将一个类型分割了存储的,所以咋还是另起一行吧,所以 int 类型就存储在一个新的单元里。
最后存储 short 类型的字段C,占 2 个字节。

图 1  中的空白空间虽然没有使用,但是它也会算作结构体的一部分,所以最终结构体 Phone 占用的存储空间是 4 * 3 = 12 字节。

做的更好些! 占用更少的存储空间

上面图 1 中显示的结构体 Phone 的内存布局中,有好多空白空间没有使用导致浪费。其实我们可以做的更好些,只需要编码时稍稍改变下结构体中字段的顺序其产生的结构会令你的程序节省不少空间。

将上面结构体 Phone 中字段 B 和字段 C 交换下位置,得到新的结构体 Phone2:

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

      
     图 2 结构体 Phone2 的内存布局

上面这个结构体计算存储空间,sizeof(Phone2) = 4 * 2 = 8 字节,比上面Phone节省了 1/3 的存储空间。

做到最好! 占用最少的存储空间

上面的虽然情况有所好转,节省了不少空间,但是还是有空白空间被浪费,而且还需要我们编码时考虑结构体字段的顺序。除此之外,还有很重要的一个因素,就是我们用 sizeof 求出的结构体大小与结构体中每个字段所占空间之和不等,虽然这一点我们现在已经清楚怎么回事,但是我们还是希望无论结构体中字段顺序如何,sizeof 求出的大小总是和结构体中所有字段所占空间之和相等。 怎么解决呢?

办法相当简单,相比你猜到了~~, 内存中数据的最小单元既然是字节,那干嘛不以字节为单位呢?所以结构体 Phone 变为如下形式: 

struct tagPhone3
{
     char   A;
     char   B[2];
     char   C[4];
}Phone3;

      
      图 2 结构体 Phone2 的内存布局

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

总结

     上面提到的三种写法,各有各的优点:

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

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

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

     只要了解是这些写法的差异性,可以视情况选用。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值