结构体和union大小的问题

本文详细解释了C/C++中结构体(struct)和共用体(union)的内存对齐原则,包括数据成员对齐规则、结构体作为成员的对齐方式及如何使用#pragmapack来控制对齐。

请牢记以下3条原则:(在没有#pragma pack宏的情况下)

1:数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储。

2:结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.)

3:收尾工作:结构体的总大小,也就是sizeof的结果,.必须是其内部最大成员的整数倍.不足的要补齐.

等你看完此3条原则,2分钟已经过去,抓紧时间,实战3分钟:

typedef struct bb
{
 int id;             //[0]....[3]
 double weight;      //[8].....[15]      原则1
 float height;      //[16]..[19],总长要为8的整数倍,补齐[20]...[23]     原则3
}BB;

typedef struct aa
{
 char name[2];     //[0],[1]
 int  id;         //[4]...[7]          原则1

 double score;     //[8]....[15]    
 short grade;    //[16],[17]        
 BB b;             //[24]......[47]          原则2
}AA;

int main()
{
  AA a;
  cout<<sizeof(a)<<" "<<sizeof(BB)<<endl;
  return 0;
}

结果是

48 24
ok,上面的全看明白了,内存对齐基本过关.

再讲讲#pragma pack().

在代码前加一句#pragma pack(1),你会很高兴的发现,上面的代码输出为

32 16
bb是4+8+4=16,aa是2+4+8+2+16=32;

这不是理想中的没有内存对齐的世界吗.没错,#pragma pack(1),告诉编译器,所有的对齐都按照1的整数倍对齐,换句话说就是没有对齐规则.

明白了不?

那#pragma pack(2)的结果又是多少呢?对不起,5分钟到了,自己去测试吧.

===============================================================

一会搞定union内存字节对齐
也是转载一个论坛的回复:

其实union(共用体)的各个成员是以同一个地址开始存放的,每一个时刻只可以存储一个成员,这样就要求它在分配内存单元时候要满足两点:   
  1.一般而言,共用体类型实际占用存储空间为其最长的成员所占的存储空间;   
  2.若是该最长的存储空间对其他成员的元类型(如果是数组,取其类型的数据长度,例int   a[5]为4)不满足整除关系,该最大空间自动延伸;   
    
  我们来看看这段代码:   
  union   mm{   
  char   a;//元长度1   
  int   b[5];//元长度4   
  double   c;//元长度8   
  int   d[3];   
  };   
  本来mm的空间应该是sizeof(int)*5=20;但是如果只是20个单元的话,那可以存几个double型(8位)呢?两个半?当然不可以,所以mm的空间延伸为既要大于20,又要满足其他成员所需空间的整数倍,即24   
    
  所以union的存储空间先看它的成员中哪个占的空间最大,拿他与其他成员的元长度比较,如果可以整除,ok

 

<think>嗯,我现在要弄清楚C语言中unionstruct的区别以及它们的用法比较。首先,我需要回忆一下之前学过的相关知识。记得struct是结构体,而union是联合体,它们都是用来组合不同类型的数据的。但具体有什么不同呢? 根据引用[1]引用[5],struct中的每个成员都有独立的内存空间,所以struct的大小是所有成员大小的总,还要考虑字节对齐的问题。而union的所有成员共享同一块内存,大小由最大的成员决定。比如,如果union有一个int一个double,那么union大小就是double的大小,因为double比int大。那这样union在内存使用上会更节省,但同一时间只能存储其中一个成员的值,对吗? 那什么时候用struct,什么时候用union呢?比如,当需要同时保存多个不同类型的数据时,用struct,因为每个成员都有自己的空间。而如果多个数据不会同时使用,用union可以节省内存。比如处理网络协议的不同数据包格式,或者表示不同的数据类型但一次只用一种,这时候union比较合适。 比如引用[5]中的例子,存储一个数据可能为整数、浮点数或字符串,可以用union,这样不需要同时分配三种类型的内存,节省空间。而struct的话,每个成员都会占用各自的空间,即使不同时使用。 再来看字节对齐的问题。struct需要考虑成员的对齐,比如一个int(4字节)后面跟一个char(1字节),可能会填充3字节以达到4字节对齐,所以总大小可能比成员总更大。而union不需要考虑不同成员之间的对齐,只需要按最大成员的对齐要求来分配空间,所以union大小就是最大成员的大小加上可能的填充。 比如引用[4]中的例子,DATE是一个union,包含double i(8字节)、int k[5](5*4=20字节)char c(1字节)。所以DATE的大小应该是20字节,但需要考虑对齐。假设系统是4字节对齐,int数组k的每个元素占4字节,总长20,所以可能不需要额外填充,所以DATE的大小是20字节。而struct data包含int cat(4字节),DATE cow(20字节),double dog(8字节)。struct data的大小需要考虑对齐,比如cat之后可能需要填充4字节使DATE cow对齐到8字节?或者要看具体编译器。最终struct data的大小可能是4 + 20(填充到8的倍数?)+8= 32?然后加上DATE max的大小20,总是32+20=52?但原题可能结果不同,可能需要具体计算。 不过用户的问题主要是比较unionstruct的区别,所以回到主题。另外,引用[2][3]提到typedef struct的用法,可能对理解结构体有帮助,但重点还是两者的区别。 总结一下,区别主要有以下几点: 1. 内存分配:struct各成员独立存储,union共享内存。 2. 大小计算:struct是所有成员大小(含对齐),union是最大成员大小。 3. 使用场景:struct用于组合多个同时使用的数据,union用于同一时间只用其中一个成员的场景。 另外,union的修改一个成员会影响其他成员的值,因为它们共享内存。而struct的成员修改互不影响。 例如,union中的一个intfloat,如果先赋值int,再赋值float,原来的int值会被覆盖。而struct中的intfloat各自存储,互不影响。 应用场景方面,union常用于类型转换、节省内存,或者处理多种数据格式但一次只用一种的情况。struct则用于数据记录,比如学生信息包含姓名、年龄、成绩等,这些信息需要同时存在。 可能还需要注意,union的初始化只能初始化第一个成员,而struct可以分别初始化各个成员。 嗯,这样应该涵盖了它们的区别用法比较。接下来,用户可能需要知道具体如何选择使用哪一个,以及实际例子。</think>### C语言中union与struct的区别及用法比较 #### 一、核心区别总结 1. **内存分配方式** - **struct(结构体)**:每个成员拥有独立的内存空间,总大小为所有成员大小(需考虑字节对齐)[^1][^5]。 例如: ```c struct A { int a; // 4字节 long *b; // 8字节(64位系统) char c[20]; // 20字节 }; ``` 大小计算:$4 + 8 + 20 = 32$ 字节(假设无填充)[^1]。 - **union(联合体)**:所有成员共享同一块内存,总大小等于最大成员的大小[^5]。 例如: ```c union DATE { double i; // 8字节 int k[5]; // 20字节 char c; // 1字节 }; ``` 大小计算:$\max(8, 20, 1) = 20$ 字节(考虑对齐可能为20字节)[^4]。 2. **数据存储特性** - **struct**:可同时存储所有成员的值,成员之间互不影响。 - **union**:同一时间只能存储一个成员的值,修改一个成员会覆盖其他成员[^5]。 3. **应用场景** - **struct**:需要同时使用多个数据成员的场景(如存储学生信息:姓名、年龄、成绩)。 - **union**:同一时间仅需使用一个成员,或需要灵活转换数据类型(如网络协议解析、类型标识联合体)。 --- #### 二、用法对比及示例 1. **struct的典型用法** 用于组合逻辑相关的数据: ```c typedef struct Student { char name[20]; int age; float score; } Student; Student s = {"Alice", 18, 95.5}; // 可同时初始化所有成员 ``` 2. **union的典型用法** 用于节省内存或类型转换: ```c union Value { int i; float f; char str[4]; }; union Value v; v.i = 65; printf("%c", v.str[0]); // 输出'A'(ASCII 65对应字符'A') ``` --- #### 三、字节对齐对大小的影响 - **struct的对齐规则**: 成员按声明顺序排列,总大小需是最大成员对齐值的整数倍。 例如: ```c struct Example { char a; // 1字节(对齐值1) int b; // 4字节(对齐值4) double c; // 8字节(对齐值8) }; ``` 实际大小:$1 + 3(填充) + 4 + 4(填充) + 8 = 20$ 字节(假设8字节对齐)[^2]。 - **union的对齐规则**: 只需满足最大成员的对齐要求。例如上述`union DATE`的大小为20字节(假设4字节对齐)[^4]。 --- #### 四、应用场景示例 1. **struct的典型场景** 存储包含多个属性的数据实体,如文件元信息: ```c struct FileInfo { char name[100]; size_t size; time_t create_time; }; ``` 2. **union的典型场景** - **类型转换**:将同一内存解释为不同类型的数据。 ```c union Converter { uint32_t num; uint8_t bytes[4]; }; ``` - **协议解析**:处理不同格式的数据包头。 --- #### 五、总结表格 | 特性 | struct | union | |---------------------|---------------------------------|--------------------------------| | **内存分配** | 成员独立存储 | 成员共享内存 | | **总大小** | 所有成员大小(含填充) | 最大成员大小 | | **数据存储** | 可同时存储所有成员 | 同一时间仅存一个成员 | | **适用场景** | 组合多个数据 | 节省内存、类型转换、多格式数据 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值