Struct和Union的sizeof计算

本文详细解析了C语言中结构体(struct)与共用体(union)的内部存储机制,包括成员对齐规则、结构体大小计算方法及实例分析。通过具体案例帮助读者理解如何计算不同类型成员组合的结构体大小。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

struct
结构体的大小不是简单的成员相加,要考虑存储空间的字节对齐
1、空结构体的大小为1
2、含有static的结构体在计算大小时不算上static变量,因为static存储在全局数据空间,而sizeof计算的是栈分配的空间

一、编译器存储结构体的准则(很重要)
  •  结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
  •  结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节;
例如:|【char】【char】【x】【x】【           int            】|
    |【                                  double                                】|
int类型不会直接接在最后一个char后面,它会在与结构体首地址的偏移量为其倍数的地方开始存储
  •  结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。
二、结构体长度求法

1.成员都相同时(或含数组且数组数据类型同结构体其他成员数据类型):
结构体长度=成员数据类型长度×成员个数(各成员长度之和);
结构体中数组长度=数组数据类型长度×数组元素个数;

2.成员不同且不含其它结构体时;
(1).分析各个成员长度;
(2).找出最大长度的成员长度M(结构体的长度一定是该成员的整数倍);
(3).并按最大成员长度出现的位置将结构体分为若干部分;
(4).各个部分长度一次相加,求出大于该和的最小M的整数倍即为该部分长度
(5).将各个部分长度相加之和即为结构体长度

3.含有其他结构体时:
(1).分析各个成员长度;
(2).对是结构体的成员,其长度按b来分析,且不会随着位置的变化而变化;
(3).分析各个成员的长度(成员为结构体的分析其成员长度),求出最大值;
(4).若长度最大成员在为结构体的成员中,则按结构体成员为分界点分界;
其他成员中有最大长度的成员,则该成员为分界点;
求出各段长度,求出大于该和的最小M的整数倍即为该部分长度
(5).将各个部分长度相加之和即为结构体长度


例子:
struct test1{ char a; 
   int b; 
   double c; 
   bool d; 
  };

 

分析:该结构体最大长度double型,长度是8,因此结构体长度分两部分:
第一部分是a、 b、 c的长度和,长度分别为1,4,8,则该部分长度和为13,取8的大于13的最小倍数为16;
第二部分为d,长度为1,取大于1的8的最小倍数为8,
两部分和为24,故sizeof(test2)=24;

struct  test2{ 
  char a; 
  test1 bb;
 int cc; 
}

分析:该结构体有三个成员,其中第二个bb是类型为test1的结构体,长度为24,且该结构体最大长度成员类型为double型,以后成员中没有double型,所以按bb分界为两部分:
第一部分有a 、bb两部分,a长度为1,bb长度为24,取8的大于25的最小倍数32;
第二部分有cc,长度为4,去8的大于4的最小倍数为8;
两部分之和为40,故sizeof(test3)=40;

struct test4{ 
 char a; 
 int b; 
}; 
struct test5{ char c; 
 test4 d; 
 double e; 
 bool f; 
};

求sizeof(test5)
分析:test5明显含有结构体test4,按例2容易知道sizeof(test4)=8,且其成员最大长度为4;则结构体test5的最大成员长度为8(double 型),考试.大提示e是分界点,分test5为两部分:
第一部分由c 、d、e组成,长度为1、8、8,故和为17,取8的大于17的最小倍数为24;
第二部分由f组成,长度为1,取8的大于1的最小倍数为8,
两部分和为32,故sizeof(test5)=24+8=32;


union

union的长度取决于其中的长度最大的那个成员变量的长度。即union中成员变量是重叠摆放的,其开始地址相同。

其实union(共用体)的各个成员是以同一个地址开始存放的,每一个时刻只可以存储一个成员,这样就要求它在分配内存单元时候要满足两点:  
  1.一般而言,共用体类型实际占用存储空间为其最长的成员所占的存储空间;  
  2.若是该最长的存储空间对其他成员的元类型(如果是数组,取其类型的数据长度,例int   a[5]为4)不满足整除关系,该最大空间自动延伸;  
例如:
union un
{
    int a[7]; //元长度4
    double b; //元长度8
    char c[10]; //元长度1
    int d[3]; //元长度4
};
可求得sizeof(un)=32;
 
union number
{ /*定义一个联合*/
int i;
struct
{ /*在联合中定义一个结构*/
char first;
char second;
}half;
}num;
可求得sizeof(number)=4, 其中大致的结构是这样的:
(高地址)【高位---------int------------低位】(低地址)
或者
(高地址)【--】【--】【-second-】【-first-】(低地址)
同一时间只有一种情况,因为union每一时刻只能存储一个成员
例子代码:

#include <stdio.h>
void main()
{
union number
{ /*定义一个联合*/
int i;
struct
{ /*在联合中定义一个结构*/
char first;
char second;
}half;
}num;
num.i=0x4241; /*联合成员赋值*/
printf("%c%c/n", num.half.first, num.half.second);
num.half.first='a'; /*联合中结构成员赋值*/
num.half.second='b';
printf("%x/n", num.i);
getchar();
}
输出结果为: 
AB 
6261

从上例结果可以看出: 当给i赋值后, 其低八位也就是first和second的值; 当给first和second赋字符后, 这两个字符的ASCII码也将作为i 的低八位和高八位。




(本文章整合了网上的一些资料并加上了自己的一些理解)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值