union和struct大小

结构体对齐与联合体详解
本文详细解析了在Windows环境下使用Visual C++时结构体成员变量的对齐规则及如何修改编译器默认对齐值的方法。此外,还介绍了联合体(union)的存储特性及其对齐规则。

1、字节对齐的细节和编译器实现相关,但一般而言,如在windows下,就VC而言,满足一下三个准则:
1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);

即:在默认情况下,VC规定各成员变量存放的起始地址相对于结构的起始地址的偏移量:sizeof(类型)或其倍数
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)

即:最大sizeof(类型)的整数倍

类型
对齐方式(变量存放的起始地址相对于结构的起始地址的偏移量)

Char   偏移量必须为sizeof(char)即1的倍数

int  偏移量必须为sizeof(int)即4的倍数

float  偏移量必须为sizeof(float)即4的倍数

double 偏移量必须为sizeof(double)即8的倍数 

Short  偏移量必须为sizeof(short)即2的倍数


简单说明:

struct DoNothing

{

};

这个sizeof(DoNothing)肯定是1的,原因是一个“没有空间”的变量如何去取它的地址呢?如果有两个不同的空struct如何去区分它们呢?这样编译器就只好这么处理了。


struct MyStruct
{


char dda;       //偏移量为0,满足对齐方式,dda占用1个字节;

double dda1;  //下一个可用的地址的偏移量为1,不是sizeof(double)=8的倍数,需要补足7个字节才能使偏移量变为8(满足对齐方式),因此VC自动填充7个字节,dda1存放在偏移量为8的地址上,它占用8个节。

int type;    //下一个可用的地址的偏移量为16,是sizeof(int)=4的倍数,满足int的对齐方式,所以不需要VC自动填充,type存/放在偏移量为16的地址上,它占用4个字节。

};//所有成员变量都分配了空间,空间总的大小为1 7 8 4=20,不是结构的节边界数(即结构中占用最大空间的类型所占用的字节数sizeof 字串2(double)=8)的倍数,所以需要填充4个字节,以满足结构的大小为sizeof(double)=8的倍数。

所以该结构总的大小为:sizeof(MyStruc)为1 7 8 4 4=24。其中总的有7 4=11个字节是VC自动填充的,没有放任何有意义的东西。


2、如何修改编译器的默认对齐值? 
1.在VC IDE中,可以这样修改:[Project]|[Settings],c/c++选项卡Category的Code Generation选项的Struct Member Alignment中修改,默认是8字节。 
2.在编码时,可以这样动态修改:#pragma pack .注意:是pragma而不是progma. 
1) n字节对齐就是说变量存放的起始地址的偏移量有两种情况:第一、如果n大于等于该变量所占用的字节数,那么偏 移量必须满足默认的对齐方式,第二、如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。
2) 结构的总大小也有个约束条 件,分下面两种情况:如果n大于所有成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数,否则是n的倍数。

 

总结,struct的大小通过以下两点即可得出:

1.数据成员对齐规则:
n字节对齐就是说变量存放的起始地址的偏移量:min(sizeof(类型),对齐方式)或其倍数.
2.整体对齐规则:
结构的总大小也有个约束条件:min(最大的sizeof(类型),对齐方式)的倍数
.



下面举例说明其用法。
#pragma pack(push) //保存对齐状态
#pragma pack(4)//设定为4字节对齐

struct test
{
char m1;
double m4;
int m3;
};

#pragma pack(pop)//恢复对齐状态

以上结构的大小为16,下面分析其存储情况,首先为m1分配空间,其偏移量为0,满足我们自己设定的对齐方式(4字节对齐),m1占用1个字节。接着开始为 m4分配空间,这时其偏移量为1,需要补足3个字节,这样使偏移量满足为n=4的倍数(因为sizeof(double)大于n),m4占用8个字节。接 着为m3分配空间,这时其偏移量为12,满足为4的倍数,m3占用4个字节。这时已经为所有成员变量分配了空间,共分配了16个字节,满足为n的倍数。如 果把上面的#pragma pack(4)改为#pragma pack(16),那么我们可以得到结构的大小为24。

 

 

3、Union

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

其实union(共用体)的各个成员是以同一个地址开始存放的,每一个时刻只可以存储一个成员,这样就要求它在分配内存单元时候要满足两点:   
  1.一般而言,共用体类型实际占用存储空间为其最长的成员所占的存储空间;   
  2.若是该最长的存储空间对其他成员的元类型(如果是数组,取其类型的数据长度,例int   a[5]为4)不满足整除关系,该最大空间自动延伸;   
  我们来看看这段代码:   

  union   mm{   
  char   a;//元长度1   
  int   b[5];//元长度4   
  double   c;//元长度8   
  int   d[3]; //元长度4
  };   

本来mm的空间应该是sizeof(int)*5=20;但是如果只是20个单元的话,那可以存几个double型(8位)呢?两个半?当然不可以,所以mm的空间延伸为既要大于20,又要满足其他成员所需空间的整数倍,,因为含有double元长度8,故大小为24。
所以union的存储空间先看它的成员中哪个占的空间最大,拿他与其他成员的元长度比较,如果可以整除就行

<think>首先,用户的问题是:“我想理解unionstruct在编程中的区别 请问unionstruct的区别”。我需要基于提供的引用内容来回答这个问题。 引用内容总结: - 引用[1]:Struct Union 的关键区别在于内存单元的分配使用。Struct 成员独立分配内存,Union 成员共享内存,节省空间。 - 引用[2]:Union 成员覆盖彼此的内存,因此 sizeof(union) 等于其最大成员的大小,而 struct 成员顺序存储,可能有填充。 - 引用[3]:Struct 所有成员同时存在,总长度等于所有成员长度之(考虑字节对齐);Union 在任何时刻只有一个成员被选中,长度等于最大成员长度。 - 引用[4]:通过代码示例展示了 struct union 的内存占用:struct 占用 12 字节(考虑对齐),union 占用 4 字节(最大成员大小)。 我的回答需要: - 使用中文。 - 结构清晰,逐步解释。 - 包含行内数学表达式使用 $...$,例如 $sizeof(union)$。 - 独立公式使用 $$...$$ 格式并单独成段(但在这个问题中,可能不需要复杂公式,所以可能不适用)。 - 在回答中引用的段落末尾自然地添加引用标识,例如 [^1]。 - 生成相关问题。 - 参考提供的引用,但以用户问题为中心。 回答结构: 1. **引言**:简要介绍 struct union 的概念。 2. **关键区别**:详细解释内存分配、使用方式、大小计算等。 3. **示例**:引用代码或简单示例来阐明。 4. **应用场景**:讨论何时使用 structunion。 5. **总结**:概括主要区别。 6. **相关问题**:生成相关问题。 确保行内数学表达式正确:例如,提到大小时用 $sizeof$,如 $sizeof(\text{union})$。 引用标识:在解释中,当引用具体内容时添加,如 [^1]。 相关问题:基于内容生成 2-3 个相关问题。 最终输出格式: - 回答部分。 - 相关问题部分。 完整响应: - 先回答用户问题。 - 然后以 "§§相关问题§§" 开头列出相关问题。</think>### Union Struct 在编程中的区别 在编程中,`struct`(结构体) `union`(联合体)都是用于组合不同类型数据的复合数据类型,但它们在内存分配、使用方式应用场景上有本质区别。下面我将逐步解释这些区别,帮助您更好地理解。 #### 1. **内存分配与大小** - **Struct (结构体)**: 所有成员同时存在,每个成员都有自己独立的内存空间。结构体的总大小等于所有成员大小,并考虑字节对齐(padding)。字节对齐是为了优化内存访问,确保数据在内存中的地址满足特定边界要求(例如,int 类型通常需对齐到 4 字节边界)。 例如,如果一个 struct 包含 `char a`(1 字节)、`int b`(4 字节) `short c`(2 字节),其大小可能为 12 字节(考虑对齐填充)[^4]。 数学表达式:$sizeof(\text{struct}) = \sum \text{成员大小} + \text{填充字节}$。 - **Union (联合体)**: 所有成员共享同一块内存空间,任何时候只有一个成员被“激活”并存储数据。联合体的大小等于其最大成员的大小,不需要额外空间。 例如,如果一个 union 包含 `char a`(1 字节)、`int b`(4 字节) `short c`(2 字节),则 $sizeof(\text{union}) = \max(1, 4, 2) = 4$ 字节[^3][^4]。 数学表达式:$sizeof(\text{union}) = \max(\text{成员大小})$。 关键区别:Struct 的内存是“叠加”的,而 union 的内存是“覆盖”的。这意味着在 struct 中修改一个成员不会影响其他成员;但在 union 中,修改一个成员会覆盖其他成员的值,因为它们共享地址[^2][^3]。 #### 2. **使用方式与数据存储** - **Struct**: 适合存储多个独立数据项,所有成员可同时访问。例如,定义一个表示学生的 struct: ```c struct Student { char name[20]; int age; float score; }; // 所有成员同时有效 ``` 这里,`name`、`age` `score` 可同时存储使用。 - **Union**: 适合存储互斥数据(即同一时刻只有一个成员有意义)。例如,定义一个表示“值”的 union,它可以存储整数或浮点数,但不能同时存储两者: ```c union Value { int intValue; float floatValue; }; // 同一时间只能使用一个成员 ``` 如果设置 `intValue = 10`,则 `floatValue` 的值会被覆盖,可能产生未定义行为[^1][^3]。 #### 3. **字节对齐的影响** 字节对齐是编译器优化机制,确保数据访问效率。在 struct 中,对齐可能导致填充字节增加大小;在 union 中,对齐基于最大成员的对齐要求。 - 示例:引用[4] 的代码展示了实际大小差异: ```c #include <stdio.h> struct u { char a; int b; short c; } U1; // sizeof(U1) = 12 (考虑对齐) union u1 { char a; int b; short c; } U2; // sizeof(U2) = 4 (最大成员 int b 的大小) ``` 输出: ``` 12 4 ``` 这里,struct大小因对齐而膨胀(例如,char 后填充 3 字节以使 int 对齐),而 union 无此问题[^2][^4]。 #### 4. **应用场景** - **Struct**: 适用于数据集合,其中所有成员相关但独立(如学生记录、点坐标)。优势是数据隔离,避免冲突;缺点是内存开销大[^1]。 - **Union**: 适用于节省内存的场景,尤其是成员互斥时(如协议解析、类型转换)。例如,在网络数据包中,一个字段可能是 IP 地址或端口号,但不同时出现。优势是内存高效;缺点是使用不当会导致数据覆盖错误[^1][^3]。 #### 5. **嵌套与高级技巧** - Struct union 可以相互嵌套(如 struct 中包含 union),以实现更复杂的数据结构。 例如: ```c struct Data { int type; union { int num; char str[10]; } value; // 根据 type 决定使用 num 或 str }; ``` 这允许在保持类型安全的同时节省空间[^1]。 #### 总结 Union struct 的核心区别在于内存模型:struct 提供独立存储,所有成员共存;union 提供共享存储,同一时间仅一个成员有效。选择时,优先 struct 用于数据独立性,优先 union 用于内存优化互斥数据[^1][^2][^3]。实际编程中,需结合字节对齐规则避免错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值