结构体和联合体(内存对齐)

结构体内存对齐:

1.为什么要进行内存对齐:

1)内存大小的基本单位是字节(byte),理论上来讲,可以从任意地址访问变量,但是实际上,cup 并非逐字节
读写内存,而是以 2,4,或 8 的倍数的字节块来读写内存,因此就会对基本数据类型的地址作出一些限制,即它的地址必须是 2,4 或 8 的倍数。那么就要求各种数据类型按照一定的规则在空间上排列,这就是对齐。
2)有些平台每次读都是从偶地址开始,如果一个 int 型(假设为 32 位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这 32bit,而如果存放在奇地址开始的地方,就需要 2 个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该 32bit 数据。显然在读取效率上下降很多。
3)由于不同平台对齐方式可能不同,如此一来,同样的结构在不同的平台其大小可能不同,在无意识的情况下,互相发送的数据可能出现错乱,甚至引发严重的问题。

2.结构体在内存的存储方式:

要想理解内存对齐,首先必须得指导结构体在内存的存储方式。

struct Student
{
	 char s_id[8];
	 char s_name[8];
	 char s_sex[4];
	 int s_age;
};
 int main()
{
	 int a;
     Student stud;
	 cout << sizeof(Student) << endl;
	 return 0;
}

内存分布如图:
在这里插入图片描述

3.内存对齐:

有了结构体的内存分布后,当然是要进行内存对齐了。

(1)首先是内存对齐的三个原则:

  1. 结构体变量的首地址,必须是结构体变量中的“最大基本数据类型成员所占字节数”的整数倍。
  2. 结构体变量中的每个成员相对于结构体首地址的偏移量,都是该成员基本数据类型所占字节数的整数倍
  3. 结构体变量的总大小,为结构体变量中 “最大基本数据类型成员所占字节数”的整数倍。

(2)内存对齐:

上边三个原则看上去很麻烦,其实挺简单的,下面上代码。

struct node
{
	 char cha;
	 int ia;
	 char chb;
};
 int main()
{
	 cout << sizeof(node) << endl;
	 return 0;
}

内存对齐后分布如图:
在这里插入图片描述
这张图是假设从0地址开始,从0开始符合第一条原则;
第二条原则:ia是int类型,占4个字节,所以ia的开始地址是4;chb道理相同。
第三条原则:chb结束时,这个结构体共占了9个字节,但这不是实际的占有字节数,又第三条原则可以知道应该是最大成员的整数倍,最大是4,此时逻辑上占了9个,所以实际占12个字节。
我们可以测试一下:
在这里插入图片描述

2.联合体:

联合体(union)与结构体(struct)有一些相似之处。但两者有本质上的不同。在结构体中,各成员有各自的内存空间。而在**联合体中,各成员共享同一段内存空间, 一个联合变量的长度等于各成员中最长的长度。**这里所谓的共享不是指把多个成员同时装入一个联合变量内, 而是指该联合变量可被赋予任一成员值,但每次只能赋一种值, 赋入新值则冲去旧值。
简而言之,就是联合体内所有成员共享同一段内存空间,用到哪个成员时,该空间就只取哪种成员。
联合体的字节数:(1)最大成员的字节数。(2)所以成员的整数倍

union UnData
{
    int st;
	char cs[2];
	 };
int main()
{
	union UnData x;
	cout << sizeof(x) << endl;
	return 0;
}

在这里插入图片描述

常见的问题:

联合体和结构体的区别:
(1)结构体的各个成员会占用不同的内存,互相之间没有影响,而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。

(2)结构体占用的内存大于等于所有成员占用的内存的总和(成员之间可能会存在缝隙),共用体占用的内存等于最长的成员占用的内存。

(3)共用体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉。

<think>嗯,用户想了解C语言结构体联合体的区别以及它们的应用场景。首先,我需要回忆一下结构体联合体的基本概念。结构体应该是一种可以将不同类型的数据组合在一起的数据结构,而联合体则是让不同的成员共享同一块内存空间。那它们的区别主要在于内存分配使用方式上对吧? 接下来,我需要从提供的引用中找到相关的信息。引用[1]提到结构体联合体是两种特殊的数据类型,有不同的特性应用场景。引用[3]详细说明结构体组合不同类型数据,联合体共享内存。引用[4]还提到了联合体在模拟寄存器操作中的应用。 我应该先解释结构体的定义用法。比如,结构体的语法是用struct关键字,可以包含多个不同类型的成员,每个成员都有自己的内存空间。例如,定义一个学生结构体,包含姓名、年龄成绩。然后给出一个代码示例,说明如何声明使用结构体。 然后是联合体部分。联合体的语法是union,所有成员共享同一块内存,大小由最大的成员决定。比如,可以定义一个数据联合体,包含整数、浮点数字符数组,这样同一时间只能使用其中一个成员。给出代码示例,展示联合体内存共享特性。 接下来是区别部分。需要比较内存分配、成员访问、初始化以及应用场景的不同。结构体各成员独立内存联合体共享内存,所以结构体内存更大,联合体更节省内存。应用场景方面,结构体适合组合数据,如学生记录;联合体适合类型转换或节省内存,比如网络数据传输或硬件寄存器操作。 应用场景部分需要具体例子。结构体用于数据库记录、图形坐标等,联合体用于协议解析、寄存器映射。这部分可以引用[4]提到的模拟寄存器操作,说明联合体如何方便地访问同一内存的不同部分。 最后生成相关问题,帮助用户进一步学习。比如结构体内存对齐联合体的类型转换,结构体联合体的嵌套使用,以及实际项目中的应用案例。 要确保回答符合用户的要求,结构清晰,用中文,正确使用LaTeX格式的数学表达式,比如在提到结构体大小时用$sizeof()$,独立公式用$$...$$。同时注意引用标记,比如在提到寄存器操作时添加[^4]。 检查是否有遗漏点,比如结构体联合体的联系,可能都需要用到自定义数据类型,或者如何嵌套使用。确保每个部分的信息准确,引用正确来源。</think>### 结构体联合体的区别应用场景 #### 1. 结构体(Struct)的概念与用法 **定义**: 结构体是C语言中用于将多个不同类型的数据组合成一个逻辑整体的复合数据类型。所有成员**独立占用内存**,按声明顺序存储。 **语法**: ```c struct 结构体名 { 数据类型 成员1; 数据类型 成员2; // ... }; ``` **示例**: 定义一个表示学生的结构体: ```c struct Student { char name[20]; int age; float score; }; ``` - **内存分配**:成员`name`、`age`、`score`分别占用独立内存,总大小为$sizeof(name) + sizeof(age) + sizeof(score)$[^2]。 - **应用场景**: - 数据库记录(如学生信息、员工档案) - 图形编程中的坐标点(如$x$、$y$、$z$三维坐标) - 网络协议封装(如IP数据包头部) --- #### 2. 联合体(Union)的概念与用法 **定义**: 联合体是C语言中允许多个成员**共享同一块内存**的复合数据类型。同一时间只能有一个成员有效,内存大小由最大成员决定。 **语法**: ```c union 联合体名 { 数据类型 成员1; 数据类型 成员2; // ... }; ``` **示例**: 定义一个存储多种数据类型的联合体: ```c union Data { int i; float f; char str[4]; }; ``` - **内存分配**:所有成员共享同一内存,大小为$max(sizeof(i), sizeof(f), sizeof(str))$,此处为4字节[^2]。 - **应用场景**: - 类型转换(如将整数的二进制表示解析为浮点数) - 协议解析(同一字段可能表示不同类型数据) - 硬件寄存器映射(如模拟32位寄存器的不同位域访问) --- #### 3. 结构体联合体的核心区别 | 特性 | 结构体(Struct) | 联合体(Union) | |--------------|-------------------------------|------------------------------| | **内存分配** | 成员独立占用内存 | 成员共享同一内存 | | **空间大小** | 各成员大小之(考虑对齐) | 等于最大成员大小 | | **成员访问** | 可同时访问所有成员 | 同一时间仅一个成员有效 | | **初始化** | 可同时初始化所有成员 | 只能初始化第一个成员 | | **典型用途** | 组合异构数据(如学生信息) | 节省内存或类型转换(如协议解析) | --- #### 4. 应用场景对比 **结构体适用场景**: - 需要同时操作多个独立数据(如$Point = \{x, y, z\}$) - 数据需长期共存(如文件记录) **联合体适用场景**: - 内存敏感场景(如嵌入式系统) - 数据互斥性(如网络协议中同一字段可能表示IP地址或端口号) - 硬件操作(通过联合体映射寄存器的不同位域) --- #### 5. 典型代码示例 **结构体联合体嵌套使用**: ```c // 定义联合体表示寄存器 union Register { uint32_t value; struct { uint8_t byte1; uint8_t byte2; uint8_t byte3; uint8_t byte4; } bytes; }; // 访问寄存器的不同部分 union Register reg; reg.value = 0x12345678; printf("Byte3: 0x%x\n", reg.bytes.byte3); // 输出0x34 ``` ---
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值