跟裤裤一起探索结构体的奥秘!

news2024/11/17 0:21:38

目录

1.结构体类型的声明

2.结构体变量的创建和初始化

2.1结构体成员的直接访问

 2.2结构体成员的间接访问

2.3结构体变量的创建和初始化 

3.结构的自引用

4.结构体内存对齐

4.1对齐规则

​4.2为什么存在内存对齐?

4.3修改默认对齐数

5.结构体传参

6.结构体实现位段

6.1什么是位段

6.2位段的内存分配

6.3位段的缺陷 


1.结构体类型的声明

struct tag
{
member-list;
}variable-list;

例如描述一个学生:

struct Stu
{
	char name[20];
	int age;
	char sex[5];
	char id[20];
};

2.结构体变量的创建和初始化

2.1结构体成员的直接访问

结构体成员的直接访问是通过点操作符(.)来访问的

使用格式为

结构体变量名.结构体成员名

 2.2结构体成员的间接访问

如果我们得到的是一个结构体的地址,而不是结构体本身,这时我们就要使用另外一个操作符来进行操作了。格式如下:

结构体指针->成员名

2.3结构体变量的创建和初始化 

结构体变量类型为:struct 类型名

这里我们也可以通过typedef来重命名一下我们的结构体名,这样子我们就可以不写struct了。

现在我们通过代码来实践一下上述内容

#include <stdio.h>
struct Stu
{
	char name[20];
	int age;
	char sex[5];
	char id[20];
};

int main()
{
	//按照结构体成员的顺序初始化
	struct Stu s = { "裤裤",18,"男","123456789" };
	printf("name:%s\n", s.name);
	printf("age:%d\n", s.age);
	printf("sex:%s\n", s.sex);
	printf("id:%s\n", s.id);
	//重命名
	typedef struct Stu Stu;
	//指定顺序初始化
	Stu s2 = {.name="短裤",.age=13,.id="1234486789",.sex="男",};
	//使用->操作符打印
	Stu *ps2 = &s2;
	printf("name:%s\n", ps2->name);
	printf("age:%d\n", ps2->age);
	printf("sex:%s\n", ps2->sex);
	printf("id:%s\n", ps2->id);
	return 0;
}

当然,我们也可以在定义结构体变量时直接typedef,使用实例如下:

typedef struct Stu
{
	char name[20];
	int age;
	char sex[5];
	char id[20];
}Stu; 

3.结构的自引用

在结构体中再创建一个自己可以吗?

struct Node
{
	int data;
	struct Node next;
};

恐怕是不可以的,只怕是子子孙孙无穷匮也,sizeof(Node)也取不到头了。这个结构体也变成无穷大的了。

那么正确的自引用方式是什么样的呢?

struct Node
{
	int data;
	struct Node*next;
};
//要先创建才能重命名
//没创建就使用重命名,内部写Node*会报错
typedef struct Node
{
	int data;
	struct Node*next;
}Node;

4.结构体内存对齐

我们已经掌握了结构体的基本使用,现在我们可以深入研讨一个问题:如何计算结构体的大小。

这个问题便是:结构体内存对齐

4.1对齐规则

我们首先要掌握结构体的对齐规则:

1.结构体的第一个成员对齐到结构体变量起始位置偏移量为0的地址处

2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

   对齐数=编译器默认的一个对齐数与该成员变量大小的较小值

   --VS2022中的默认对齐数是8

   --Liunx中gcc没有默认对齐数,对齐数就是成员自身的大小

3.结构体总大小为所有成员对齐数中的最大对齐数的整数倍

4.如果嵌套了结构体,嵌套的结构体成员对齐到自己的成员的最大对齐数处,结构体的整体大小就是所有成员的最大对齐数(含嵌套结构体成员)的整数倍

现在我们来看一段代码。

int main()
{
	struct S1
	{
		char c1;
		int i;
		char c2;
	};
	printf("%d\n", sizeof(struct S1));
}

再来看一段代码

int main()
{
	struct S3
	{
		double d;
		char c;
		int i;
	};
	printf("%d\n", sizeof(struct S3));
}

最后看一段代码

struct S3
{
	double d;
	char c;
	int i;
};
struct S4
{
	char c1;
	struct S3 s3;
	double d;
};
printf("%d\n", sizeof(struct S4));
}

4.2为什么存在内存对齐?

有两个原因

1.平台原因(移植原因):

不是所有的硬件平台都可以访问任意地址上的任意数据的;某些硬件平台只能在特定地址处取出特定类型的数据,否则会出现硬件异常的问题。

2.性能原因:

数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要两次内存访问;而对齐的内存访问一次即可。

假设一个处理器一次在内存中取出八个字节,地址必须是8的整数倍,如果我们能保证所有的double类型的地址都能对齐到8的倍数,那么我们就可以通过一次内存操作来完成读写操作了。否则我们可能需要两次取内存操作才能完成读写操作。

总结:结构体的内存对齐是拿空间来换时间的做法。

那么,我们在设计结构体的时候,既要满足对齐又要节省空间,就可以把占用空间小的成员尽量集中在一起。

4.3修改默认对齐数

#pragma这个预处理命令可以改变编译器的默认对齐数。格式如下

#pragma pack(数字)//设置默认对齐数为括号内的数字
#pragma pack()//括号内没有数字,表示还原默认对齐数

5.结构体传参

//结构体传参
void print1(struct S s)
{
	printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S* ps)
{
	printf("%d\n", ps->num);
}
int main()
{
	print1(s); //传结构体
	print2(&s); //传地址
	return 0;
}

请大家思考一个问题,print1和print2函数,哪个性能更高?

答案是print2函数

原因:

        函数传参的时候,参数是需要压栈的,会有时间和空间上的系统开销 。

        如果传递一个结构体对象的时候采用传值调用,在压结构体入栈的时候会导致系统开销          过大,而导致性能下降。

        因此,我们采取传址调用。

6.结构体实现位段

6.1什么是位段

位段的声明和结构是类似的,有两个不同:

1.位段的成员必须为int类型,有符号无符号都可,但在C99标准中,位段也可选择其他类型。

2.位段的成员名后面有一个冒号和一个数字。数字表示其占用的比特位

下面来实现一个位段类型

struct A
{
	int _a : 2;//占用2个比特位
	int _b : 5;//占用5个比特位
	int _c : 10;//占用10个比特位
	int _d : 30;//占用30个比特位
};

6.2位段的内存分配

位段的几个成员可能在同一个字节中,这些有些成员的起始位置就并不是某个字节的起始位置,但是内存是给每一个字节分配一个地址,那么字节内部的比特位是没有地址的。所以不能对位段的成员使用取地址操作符,也就代表我们不能用scanf来给位段赋值,我们赋值的唯一方法是先输入放在一个变量中,然后赋值给位段的成员。

	Struct A b;
    int a = 2 = 8;
	b._a = a;

那么A占的内存大小是多少呢?

  •  a,b,c,d一共47比特位,但是我们却占用了八个字节64比特位,因此,位段节省空间的能力也是有限的。

那么位段的分配到底是怎么样的呢?

当一个结构体包含两个位段,第二个位段比较大,无法容纳于第一个位段剩余的位时, 是舍弃剩余的位还是利用呢?

我们以下列程序举例:

struct S
{
	char a : 3;
	char b : 4;
	char c : 5;
	char d : 4;
};
//内存如何分配?
int main()
{
	struct S s = { 0 };
	s.a = 10;
	s.b = 12;
	s.c = 3;
	s.d = 4;
	return 0;
}

我们先假设一下我们位段的分配方式

  1. 假设位段在一个字节内部是从高地址到低地址分配。
  2. 假设当一个结构体包含两个位段,第二个位段比较大,无法容纳于第一个位段剩余的位时, 是舍弃。

现在我们来画一下图!

现在我们只需要在系统中验证一下是否按照我们预料的存储即可。 

  •  通过验证,我们发现我们的猜想是正确的。

位段虽然能帮助我们节约内存,但是也有许多缺陷,尤其在跨平台问题上有很大的缺陷。

6.3位段的缺陷 

1.int型位段成员被当作有符号数还是无符号数不确定

2.位段的最大位数不确定:在16位机器上int型最大为16位,而在32位系统上则为32位。

3.位段的成员在内存中是从高地址向低地址分配还是从低地址向高地址分配未定义

4.当一个结构体包含两个位段,第二个位段比较大,无法容纳于第一个位段剩余的空间时,剩余的空间是利用还是舍弃不可知。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1619990.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GUI测试首推!TestComplete 帮助有效缩短 40-50% 测试时长!

TestComplete 是一款自动化UI测试工具&#xff0c;这款工具目前在全球范围内被广泛应用于进行桌面、移动和Web应用的自动化测试。 TestComplete 集成了一种精心设计的自动化引擎&#xff0c;可以自动记录和回放用户的操作&#xff0c;方便用户进行UI&#xff08;用户界面&…

Pyside6:多行按钮点击判断序号

在Pyside开发过程中会遇到这么个问题&#xff1a;当多个按钮在很多行中&#xff0c;需要在点击槽函数中确认按钮的行。 普通的按钮点击信号如下&#xff1a; clicked() 该信号并未有任何参数&#xff0c;无法得到有效的信息&#xff0c;那么如何完成点击哪个确定是哪个按钮呢…

分类预测 | Matlab实现RIME-BP霜冰优化BP神经网络多特征分类预测

分类预测 | Matlab实现RIME-BP霜冰优化BP神经网络多特征分类预测 目录 分类预测 | Matlab实现RIME-BP霜冰优化BP神经网络多特征分类预测分类效果基本介绍程序设计参考资料 分类效果 基本介绍 1.RIME-BP霜冰优化BP神经网络多特征分类预测&#xff08;Matlab实现完整源码和数据&a…

Linux SDIO-WiFi 协议栈

Linux SDIO-WiFi 协议栈 1. 简介2. BCMDHD2.1 WiFi模组2.2 驱动初始化&#xff08;dhd_module_init&#xff09; 3. Broadcom fullmac WLAN 1. 简介 2. BCMDHD BCMDHD&#xff1a;Broadcom Dongle Host DriverSIP&#xff1a;System In Package 2.1 WiFi模组 2.2 驱动初始化…

条件生成对抗网络(cGAN)在AI去衣技术中的应用探索

随着深度学习技术的飞速发展&#xff0c;生成对抗网络&#xff08;GAN&#xff09;作为其中的一个重要分支&#xff0c;在图像生成、图像修复等领域展现出了强大的能力。其中&#xff0c;条件生成对抗网络&#xff08;cGAN&#xff09;通过引入条件变量来控制生成模型的输出&am…

互联网大厂ssp面经,数据结构part3

1. 哈希表的原理是什么&#xff1f;如何解决哈希碰撞问题&#xff1f; a. 原理&#xff1a;通过哈希函数将每个键映射到一个唯一的索引位置&#xff0c;然后将值存储在对应索引位置的存储桶中。 b. 关键&#xff1a;将不同的键映射到不同的索引位置&#xff0c;以实现快速的插…

Spring Boot 集成 EasyExcel 3.x

Spring Boot 集成 EasyExcel 3.x Spring Boot 集成 EasyExcel 3.x 本章节将介绍 Spring Boot 集成 EasyExcel&#xff08;优雅实现Excel导入导出&#xff09;。 &#x1f916; Spring Boot 2.x 实践案例&#xff08;代码仓库&#xff09; 介绍 EasyExcel 是一个基于 Java 的、…

社交的神奇好处你都知道吗?

聊天交友软件是人们日常生活中不可或缺的一部分&#xff0c;有些需要花费大量金钱才能享受完整的功能&#xff0c;但也有一些不需要花费金钱的聊天交友软件&#xff0c;如微信、QQ等。这些软件提供了多种交流方式&#xff0c;让用户可以方便地结识新朋友、扩大社交圈子&#xf…

基于SpringBoot的合家云社区物业管理平台 - 项目介绍

合家云社区物业管理平台 2.合家云需求&设计 2.1 项目概述 2.1.1 项目介绍 合家云社区物业管理平台是一个全新的 ”智慧物业解决方案“&#xff0c;是一款互联网的专业社区物业管理系统。平台通过社区资产管理、小区管理、访客管理、在线报修、意见投诉等多种功能模块&a…

游戏陪玩系统app

游戏陪玩系统APP为用户提供了一个便捷的平台&#xff0c;让他们能够轻松找到合适的陪玩者&#xff0c;一同享受游戏的乐趣。以下是对您提到的功能的详细解释&#xff1a; 游戏约玩&#xff1a; 在陪玩APP上&#xff0c;用户可以浏览陪玩者的信息&#xff0c;包括他们的游戏技能…

YOLOv8 训练自己的数据集(20240423)

环境搭建请参考&#xff1a;Win10 搭建 YOLOv8 运行环境&#xff08;20240423&#xff09;-CSDN博客 环境测试请参考&#xff1a;本地运行测试 YOLOv8&#xff08;20240423&#xff09;-CSDN博客 一、使用 YOLOv8 的 coco128 数据集熟悉一下如何训练和预测 1.1、在项目根目录…

新的ChatGPTPlus(GPT4)支付渠道?怎么付费充值?

GPT4多少钱一个月 GPT4一个20美元。作为最优秀的语言模型之一&#xff0c;GPT-4为您带来无与伦比的生产力体验。 除了出色的自然语言处理能力&#xff0c;GPT-4还引入了创新的代码解释器功能和强大的插件扩展&#xff0c;进一步提升了您的工作效率和创造力。 代码解释器功能&…

excel一列同乘同一个数

excel一列同乘同一个数 第一种方法&#xff08;excel本身功能&#xff09; 在空白区域输入要乘以的数&#xff0c;比如0.5 右键选择复制 选中需要乘以的单元格&#xff0c;选择性粘贴 点击乘&#xff0c;选择确定 删除0.5后也不会改变值 第二种方法&#xff08;方方格子…

LLama的激活函数SwiGLU 解释

目录 Swish激活函数 1. Swish函数公式 LLaMA模型中的激活函数 1. SwiGLU激活函数 2. SwiGLU激活函数的表达式 3. SwiGLU激活函数的优势 Swish激活函数 Swish是一种激活函数&#xff0c;其计算公式如下&#xff1a; 1. Swish函数公式 Swish(x) x * sigmoid(x) 其中&am…

开源协议的对比和商业上的安全使用

开源协议的对比和商业上的安全使用 开源组件是&#xff1a;“任何人都可以自由使用、更改和共享&#xff08;以修改或未修改的形式&#xff09;的软件”。当今企业依靠开源来加速开发、降低成本和推动创新。对开放源码的糟糕管理可能会使组织面临安全、法律和操作风险。 使用…

【Python】爬虫-基础入门

目录 一、什么是爬虫 二、爬虫的主要用途 三、学会爬虫需要掌握的技能 四、爬虫使用的语言 五、编写爬虫需要的库&#xff0c;以python为例 六、爬虫示例-python 示例一 示例二 示例三 一、什么是爬虫 爬虫&#xff0c;又称网络爬虫或网页爬虫&#xff0c;是一种用来自…

解读DreamFusion:一个引人注目的AI生成内容领域的项目

什么是DreamFusion&#xff1f; DreamFusion使用2D扩散模型来实现文本到3D生成的任务。这项技术在ICLR 2023上获得了杰出论文奖&#xff0c;并成为了许多科研工作的基准。 简而言之&#xff0c;DreamFusion的目标是在没有3D数据监督的情况下&#xff0c;利用已有的2D生成模型根…

11 JavaScript学习:事件

Html事件 HTML 中有很多事件可以用来与用户交互&#xff0c;以下是一些常见的 HTML 事件及其详细解释和举例&#xff1a; click 事件&#xff1a;当用户点击元素时触发。 <button onclick"myFunction()">点击我</button>dblclick 事件&#xff1a;当用…

【二】ECharts----【异步加载数据】

目录 零.前言 一.异步加载数据 1.1简介 1.1.1一个使用$.get()获取json数据并加载的例子 1.2数据的动态更新【重要】 1.2.1一个使用random随机生成的动态更新 完整代码如下&#xff1a; 二.加载中动画 零.前言 【一】ECharts----【基本概念、基本实例】-CSDN博客 一.…

锐捷网络闪耀高博会:智慧教育数字基座引领教育数字化新浪潮

4月15日,第61届中国高等教育博览会(简称“高博会”)在福州盛大开幕,在这次教育高端装备展示、教学改革成果交流、校企云集的行业盛会上,围绕构建智慧教育数字基座,锐捷网络携全场景智慧教育方案亮相,极简以太全光网、高校桌面云、5G多网融合等创新方案纷纷登场,吸引了众多观众驻…