C中结构体与共用体的内存对齐

C中的结构体&共用体内存对齐

1.为何存在内存对齐

​ 大致的说法如下:
a.为了方便移植,某些平台只能在特定地址处区某些特定类型的数据
b.为了提高效率,对于访问未对齐的内存,处理器需要做两次访问,而对齐的内存访问仅需要一次。
​ 以32位机器来说,当一个字符型的数据与一个整型数据依次存储,char a int b
​ 考虑到系统的数据线宽度为32,当访问a时因为a仅占一个字节,当不存在内存对齐时CPU必然会访问到b的某个位置,于是当我们接着访问b时处理器就需要做2次访问。
根本上来说,结构体的内存对齐就是拿空间换取时间。

2.结构体的内存对齐规则

1.第一个成员在与结构体变量偏移量为0的地址处,也就是说结构体的起始地址与其第一个成员的地址是等价的。
2.其他成员变量要对齐到其对齐数的整数倍地址处,
对齐数 = min{编译器默认对齐数,该成员占用字节数};
以VS,VSCODE为例,编译器默认对齐数为8;
3.结构体的总大小为最大对齐数的整数倍
4.如果存在嵌套结构体,该内部嵌套的结构体对齐到自己的成员的整数倍,外部结构体即所有的最大对齐数的整数倍(包括嵌套结构体)

举例
a.`struct u1`

`{`

  `char q;`//对齐数为1,//q本来占一个字节,但是

  `int data;`//对齐数为4,因此其对齐位置要到4的倍数,这里是4,故q也要占用四个字节,浪费了三个字节

  `char w;`//与q同理

`};`

最终占用4*3=12个字节。

`b.struct u2 { char c1; char c2; int i; }; //因为i的对齐数为4,所以c1占用一个字节,c2占用三个字节,i占用4个字节,故占用八个字节`

`c.struct u3 { double d; char c; int i; };//double的对齐数为8,因此整个结构体的字节数必须为8的倍数,c占四个字节,i占四个字节,共16个字节`

`d.struct u4 { char c1; struct u3 u; double d; };//首先u的最大对齐数在前面已经求得为8,d也是8,所以必须为8的倍数,而u本身占用16字节,故最终共占用32字节。``
3.共用体的内存对齐规则

​ 我们知道,共用体的成员共用一块内存空间,其大小至少是最大成员的大小。当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

举例
union w
{
  char c[5];//对齐数为1,至少占用5字节
  int i;``//对齐数为4,
};//综上,空间大小至少大于5,但同时要是最大对齐数4的倍数,故占用8字节空间

union Un2
{
 short c[7];//对齐数为2,至少占用2*7=14字节`
 int i;//对齐数为4`
};综上占用16字节
4.启示

在编写程序时,为节省空间,可适当将占用内存小的集中在一起,如选择
struct S2 { char c1; char c2; int i; };而非struct S1 { char c1; int i; char c2; };
还可以修改默认对齐数,如

#pragma pack(8)//设置默认对齐数为8` 
struct S1 { char c1; int i; char c2; };` 
#pragma pack()//取消设置的默认对齐数,还原为默认`

部分参考:https://www.bilibili.com/video/BV1TT4y1F7Z9?p=184

C语言结构体共用体允许开发者以一种更加紧凑和相关的方式组织数据,这在需要处理具有不同数据类型的复合数据时尤其有用。为了深入理解如何通过这些自定义数据类型进行内存的有效管理,推荐你查阅《C语言结构体共用体教程》。这本书将为你提供结构体共用体的基础知识,以及如何在项目应用它们以提高内存效率的具体示例。 参考资源链接:[C语言结构体共用体教程](https://wenku.csdn.net/doc/7tj05we6v8?spm=1055.2569.3001.10343) 结构体能够将不同类型的变量组合起来,创建一个新的数据类型。这种类型允许你将相关的数据组织成一个逻辑单元。例如,如果你正在编写一个学生信息系统,你可能会创建一个包含学生姓名、学号、成绩等信息的结构体。这样的数据组织不仅可以简化数据管理,还能够使内存分配更加高效,因为所有的相关信息都是作为单一对象存储的。 使用结构体进行内存管理的一个关键方面是结构体内存对齐。编译器通常会根据结构体成员的最大对齐要求来分配内存,这样可以保证数据的高效访问。例如: ```c struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }; ``` 在这里,`struct student` 将根据最大的成员类型(在这个例子是 `float` 类型的 `score`)来对齐内存。结构体数组的内存对齐会更加复杂,因为数组每个元素都需要按照最大成员类型对齐共用体(Union)则提供了另一种内存管理的手段。共用体的所有成员共享相同的内存位置,这意味着在任意时间点,共用体只能够存储一个成员的值。这使得共用体非常适合于那些需要存储多种数据类型但同一时间只使用一种的情况,从而节省内存。例如: ```c union data { int i; float f; char str[4]; }; ``` 在上面的共用体示例,所有成员共享相同的内存空间。如果存储了一个整数,那么存储的浮点数和字符串将会被覆盖。 在实际编程结构体共用体可以根据具体需求灵活地结合起来使用。例如,你可以在同一个结构体嵌套共用体,根据不同的情况选择存储不同类型的数据。这种做法在处理具有多种可能状态的系统时非常有用,比如在状态机的设计。 学习和掌握了结构体共用体的内存管理技巧后,你可以更加高效地编写代码,减少内存浪费。为了进一步扩展你的知识,建议在解决了当前问题后继续深入学习《C语言结构体共用体教程》,以获得更多的见解和技巧,提升你的编程能力。 参考资源链接:[C语言结构体共用体教程](https://wenku.csdn.net/doc/7tj05we6v8?spm=1055.2569.3001.10343)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值
>