如何计算结构体及共用体大小

对于结构体

 先介绍一个相关的概念——偏移量偏移量指的是结构体变量中成员的地址和结构体变量地址的差。结构体大小等于最后一个成员的偏移量加上最后一个成员的大小。显然,结构体变量中第一个成员的地址就是结构体变量的首地址。因此,第一个成员i的偏移量为0。第二个成员c的偏移量是第一个成员的偏移量加上第一个成员的大小(0+4),其值为4;第三个成员j的偏移量是第二个成员的偏移量加上第二个成员的大小(4+1),其值为5。
  实际上,由于存储变量时地址对齐的要求,编译器在编译程序时会遵循两条原则:一、结构体变量中成员的偏移量必须是成员大小的整数倍(0被认为是任何数的整数倍) 二、结构体大小必须是所有成员大小的整数倍。
  对照第一条,上面的例子中前两个成员的偏移量都满足要求,但第三个成员的偏移量为5,并不是自身(int)大小的整数倍。编译器在处理时会在第二个成员后面补上3个空字节,使得第三个成员的偏移量变成8。
  对照第二条,结构体大小等于最后一个成员的偏移量加上其大小,上面的例子中计算出来的大小为12,满足要求。
  再看一个满足第一条,不满足第二条的情况
  struct stu2
  {
  int k;
  short t;
  };
  成员k的偏移量为0;成员t的偏移量为4,都不需要调整。但计算出来的大小为6,显然不是成员k大小的整数倍。因此,编译器会在成员t后面补上2个字节,使得结构体的大小变成8从而满足第二个要求。由此可见,大家在定义结构体类型时需要考虑到字节对齐的情况,不同的顺序会影响到结构体的大小。对比下面两种定义顺序
  struct stu3
  {
  char c1;
  int i;
  char c2;
  }
  struct stu4
  {
  char c1;
  char c2;
  int i;
  }
  虽然结构体stu3和stu4中成员都一样,但sizeof(struct stu3)的值为12而sizeof(struct stu4)的值为8。
  如果结构体中的成员又是另外一种结构体类型时应该怎么计算呢?只需把其展开即可。但有一点需要注意,展开后的结构体的第一个成员的偏移量应当是被展开的结构体中最大的成员的整数倍。看下面的例子:
  struct stu5
  {
  short i;
  struct
  {
  char c;
  int j;
  } ss;
  int k;
  }
  结构体stu5的成员ss.c的偏移量应该是4,而不是2。整个结构体大小应该是16。

(1),结构体变量的首地址能够被其最宽基本类型成员大小所整除。
(2),结构体每个成员相对于结构体首地址的偏移量(offset)都是该成员大小的整数倍,如有需要,编译器会在成员之间加上中间填充字节。
(3)结构体总大小为结构体最宽基本类型成员大小的整数倍,如有需要,编译器会在最末一个成员之后加上末尾填充字节。
第(2)、(3)条准则决定了结构体变量占据内存空间的大小。
基本类型指:char,short,int,float,double。
数据宽度即其sizeof的大小。

eg:struct {char c;short s;float f;}A,struct{char c;float f;short s;}B;
则sizeof(A)=?,sizeof(B)=?
解:A中,char占1字节,short占2,则short相对于结构体首地址的offset(偏移量)=1,为满足准则(2),必须添加中间填充字节1;float占4字节,相对于结构体首地址offset=(1+1+2)即4,满足准则(2)。此时结构体大小为(1+1+2+4)=8,是最宽基本类型float整数倍,满足(3)。所以可得出:sizeof(A)=8;

对于B:B中,char占1,float占4,则float相对于结构体首地址的offset=1,为满足准则(2),必须添加中间填充字节3;short占2,相对于结构体首地址offset=(1+3+4)即8,是short所占字节的整数倍,满足准则(2)。此时结构体大小为(1+3+4+2)=10,不是最宽基本类型float的整数倍,这时,末尾必须添加末尾填充字节2,所以最后总大小为12;

总结:分析时只要这样即可:
对于A:1 1 2    4 (红色为插入部分,写时,中间要留够空格)
对于B:1 3 4    2 2
这样就可以直观的得到结构体大小。

迁移eg:struct{float f;int I;short s;}C; 则sizeof(C)=?(答案:12)

知识扩展1:若出现结构体嵌套,则准则(2)、(3)应改为:
(2),复合成员相对于结构体首地址的偏移量是复合成员中最宽基本类型成员大小的整数倍。
(3),结构体总大小为结构体最宽基本类型成员大小整数倍。
eg:
struct
{
float f;
char c;
double d;
struct
{
double d1;
float f1;
double d2;
char c1;
}A
}B;
则sizeof(B)=?
解:先计算A大小:8      4    4    8    1    7(红色为插入部分),得到为32;
所以对于B,一开始排列为: 4 1 8 32;
1的offset=4,所以4与1间要添上3。变为:
4 3 1    8    32;
此时8的offset=8,满足准则2,32的offset=16,是A中最宽基本类型double所占字节的整数倍,满足准则2;此时B大小为48,是B中最宽基本类型double的整数倍,满足准则3.所以最后sizeof(B)=48;

知识扩展2,若结构体内部出现数组,则准则2应为:
(2),数组相对于结构体首地址的offset是该数组成员大小的整数倍。
eg :struct {double d[2];char*c;}C; 则sizeof(C)=?
解:double大小为8字节,所以double[2]为16;而指针大小均为4,
所以C可排列为:
16     4 4
得到sizeof(C)=24;


对于共用体:
原则上,共用体大小取决于占据最多内存的成员的长度。但字节对齐准则(3)仍然成立。Eg:
Union
{
char c;
double d;
}e;
则sizeof(e)=16;

由于编译器不同,有的sizeof(e)=8.

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值