嵌入式第十六课!!!结构体与共用体

一、结构体

结构体是一种数据类型,它的形式是这样的:

struct 结构体名

{        

        结构体成员语句1;

        结构体成员语句2;

        结构体成员语句3;

};

举个例子:

struct Student
{int id;char name[20];float score;
};

我们创建了一个数据类型Student,在这个声明里面,创建了三个变量: int型 id  ,   字符数组name[20] ,float型score;在声明的花括号  {  }  里面,要注意添加分号 “ ; ”,不然系统编译时会报错。

在主函数使用这个数据类型的时候:

struct Student
{int id;char name[20];float score;
};int main(void)
{s.id = 1;strcpy(s.name, "zhangsan");s.score = 97.5;printf("%d, %s, %f,%d-%d-%d \n", s.id, srname, s.score);return 0;
}

我们在主函数里定义了一个变量s,t它的数据类型Student,在给它赋值的时候,要按如上方式,依次赋值;

在使用结构体这种数据类型时,可以进行结构体嵌套:

struct Student
{int id;char name[20];float score;struct Date birthday;
};int main(void)
{s.id = 1;strcpy(s.name, "zhangsan");s.score = 97.5;s.birthday.year = 2002;s.birthday.month = 3;s.birthday.day = 12;printf("%d, %s, %f,%d-%d-%d \n", s.id, srname, s.score, s.birthday.year, s.birthday.month, s.birthday.day);return 0;

结构体初始化

在进行设定变量s时,可以直接进行初始化:

struct Student
{int id;char name[20];float score;struct Date birthday;
};int main(void)
{struct Student s = {1, "zhangsan", 97.5, {2002, 3, 12}};printf("%d, %s, %f,%d-%d-%d \n", s.id, srname, s.score, s.birthday.year, s.birthday.month, s.birthday.day);return 0;

结构体嵌套的部分用花括号 { } 隔开;

也可以对部分结构体成员进行初始化:

struct Student
{int id;char name[20];float score;struct Date birthday;
};int main(void)
{struct Student s = {.id = 1,.score = 97.5,.birthday = {.year = 2002,}};
}	

其余未初始化的结构体成员变量为0;

为了在调用函数的时候,改变主调函数里struct 里结构体成员的值,我们可以通过指针来进行传参:

void printStudent(struct Student *p)
{printf("%d, %s, %f\n", p->id, p->name, p->score);
}
int main(void)
{struct Student a[3] = {{1, "zhangsan", 97.5},{2, "lisi", 98},{3, "wanghu", 95}};int len = sizeof(a) / sizeof(*a);printStudents(a, len);return 0;
}

需要注意的是,结构体成员指针不能写为(*p).id 或(*p) . name等,正确的编程规范应该为:p -> id

p -> name的格式;

使用指针传递的方式,占用字节较少,cpu运行速率较快;而普通的变量值传递会消耗很多空间,所以我们基本不用。

结构体数组

void printStudent(struct Student *p)
{printf("%d, %s, %f\n", p->id, p->name, p->score);
}void printStudents(struct Student a[], int len)
{int i;for(i = 0;i < len;++i){printStudent(a + i);}
}
int main(void)
{struct Student a[3] = {{1, "zhangsan", 97.5},{2, "lisi", 98},{3, "wanghu", 95}};int len = sizeof(a) / sizeof(*a);printStudents(a, len);return 0;
}

结构体成员按从前往后的顺序存储到数组里面;

同时,结构体数组元素之间是不能进行比较的,如a[0]和a[1],但是a[0].id 与 a[1].id之间是可以比较的。

结构体字节大小

在计算结构体大小前,我们要先厘清一个概念:

内存对齐:

在存储数据的时候,为了防止cpu为了访问一个数据,要读取两次内存空间的情况发生,在存储数据的时候,偏移量要可以整除存储的数据类型大小;

为了清晰易懂,请大家记住这三条准则,就可以又快又准确的计算出结构体所占的字节大小:

1.默认按CPU位数对齐(64位系统按8字节对齐),即最终地址为8的整数倍。

2.找结构体里最长字节的成员,以它的字节大小为基准对齐。

3.按照结构体的声明顺序,依次将成员保存在结构体内存中,最终保存的偏移量 / sizeof(成员) == 0。

如果是数组的话,就按其基类型的字节长度进行对齐;举个例子:

struct Demo
{char c;short d;int i ;
};int main(void)
{struct Demo s;printf("%d\n",sizeof(s));
}

sizeof (s) = 8字节;

0123456789
char  cshort  dint i

上图分别为存储变量的首地址,其中int 型变量占4个字节,加上前面的一共占8个字节;

这种方法势必会浪费一些空间,但是这种方式可以换取CPU的读写速率。

共用体

举个例子:

union Demo
{int i;short s;char c;
};

这是共用一段内存空间的数据类型,其共用体成员语句的内存空间相互彼此覆盖,打印值的话,系统会打印出最后一个覆盖的成员变量的值。

需要注意的是,共用体所有成员的地址都顶头写,我们可以利用这种特性来判断系统存储的方式是打断还是小端:

union Demo
{int i;short s;char c;
};int main(void)
{union Demo d;d.i = 1;union Demo *p;p = &d;fn(&d);if(d.c == 1){puts("little");}else{puts("big");}

枚举类型

这是一种自定义数据类型,并设定取值范围的数据类型:

enum Week
{Sun, Mon, Tue , Wes, Thu, Fri, Sat
};int main(void)
{enum Week w;w = Sun;printf("%d\n", w + 1);

在声明语句的时候,写入week所有的可能性,在调用时,使用这种数据类型的变量在枚举常量里任取其一:其实枚举常量里列举的取值可能性,实际上就是给整型常量0,1,2,3……等依次赋值;如果重置第一个常量Sun 赋值为2时,接下来的常量会依次赋为3,4,5,6……,如果从Mon开始重置赋值的话,Sun的值为0;

由此可以看出,它和整型是兼容的。

typedef定义类型

这种数据类型的实际上是给已有的数据类型换一个名字:

typedef int INT;typedef struct Demo
{int i;short s;char c;
}Demo, *PDEMO;typedef void (*pfn)(void);
typedef pfn ARRAY[10];int main(void)
{ARRAY a;INT s;printf("%lu\n" ,sizeof(a));return 0;
}

在主函数里,s是int型变量;a是一个由函数指针构成的元素个数为10的数组,其sizeof(a)= 80

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

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

相关文章

java web 实现简单下载功能

java web 实现简单下载功能 项目结构├── src\ │ ├── a.txt │ └── com\ │ └── demo\ │ └── web\ │ ├── Cookie\ │ ├── download\ │ ├── homework\ │ ├── serv…

虚幻基础:模型穿模

能帮到你的话&#xff0c;就给个赞吧 &#x1f618; 文章目录模型穿模模型之间的阻挡是否正确设置模型是角色的组件&#xff1a;角色的组件不会与场景中其他的物体发生阻挡但可以发生重叠模型穿模 模型之间的阻挡是否正确设置 模型是角色的组件&#xff1a;角色的组件不会与场…

【Linux】linux基础开发工具(二) 编译器gcc/g++、动静态库感性认识、自动化构建-make/Makefile

文章目录一、gcc/g介绍二、gcc编译选项预处理编译汇编链接三个细节三、动静态库感性认识动静态库的优缺点四、自动化构建-make/Makefile背景知识初步上手Makefilemakefile的推导过程makefile语法一、gcc/g介绍 我们之前介绍了编辑器vim&#xff0c;可以让我们在linux上linux系统…

CentOS 7 上使用 Docker 安装 Jenkins 完整教程

目录 前言 准备工作 系统要求 检查系统信息 更新系统 安装Docker 第一步:卸载旧版本Docker(如果存在) 第二步:安装必要的软件包 第三步:添加Docker官方仓库 第四步:安装Docker CE 第五步:启动Docker服务 第六步:验证Docker安装 第七步:配置Docker用户权限…

30.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--单体转微服务--公共代码--用户上下文会话

在前面的文章中&#xff0c;我们会看到使用ContextSession来获取当前用户的UserId和UserName。这篇文章我们就一起来看看如何实现ContextSession。 一、ContextSession的实现 我们在公共类库SP.Common中创建一个名为ContextSession的类&#xff0c;用于获取当前请求的用户信息。…

BaseDao

#### 10.1 DAO概念> DAO&#xff1a;Data Access Object&#xff0c;数据访问对象。 > > Java是面向对象语言&#xff0c;数据在Java中通常以对象的形式存在。一张表对应一个实体类&#xff0c;一张表的操作对应一个DAO对象&#xff01;>> 在Java操作数据库时&a…

USRP捕获手机/路由器数据传输信号波形(中)

目录&#xff1a; USRP捕获手机/路由器数据传输信号波形&#xff08;上&#xff09; USRP捕获手机/路由器数据传输信号波形&#xff08;中&#xff09; USRP捕获手机/路由器数据传输信号波形&#xff08;下&#xff09; 三、双工通信信号捕获 3.1 信号接收系统 5805e6Hz&a…

使用 Kiro AI IDE 3小时实现全栈应用Admin系统

Hello&#xff0c; 大家好&#xff0c;我是程序员海军, 全栈开发 |AI爱好者 &#xff5c; 独立开发。 之前我是采用Node生态开发的大模型以及MCP Server,大模型开发的生态主要是Python语言&#xff0c;为了更好的学习大模型开发&#xff0c;于是开了新坑。开始学习Python, 以及…

浏览器pdf、image显示

浏览器地址栏 pdf data:application/pdf;base64, data:application/pdf;base64,JVBERi0xLjcKJeLjz9MKMjMgMCBvYmoKPDwv image data:image/jpeg;base64, data:image/jpeg;base64,/9j/4Q3fRXhpZgAATU0AKgAAAAgABwE

《Linux运维总结:银河麒麟V10 SP3启动docker容器报错permission denied》

总结&#xff1a;整理不易&#xff0c;如果对你有帮助&#xff0c;可否点赞关注一下&#xff1f; 更多详细内容请参考&#xff1a;Linux运维实战总结 一、环境信息 二、背景 1、使用docker启动一个nginx容器&#xff0c;报错信息如下&#xff1a; docker: Error response from…

PDF源码解析

PDF源码解析打开PDF解析PDF​0. 文件头关键信息解析技术原理图解文件头的重要性实际文件结构示例开发者注意事项历史背景1. 根目录整体结构关键字段解析核心概念解释实际应用场景完整对象关系图技术总结2. 页面树对象结构关键字段解析页面树工作原理技术要点总结实际应用3. 图像…

java开闭原则 open-closed principle

基本知识 1.核心思想&#xff1a;面向抽象编程 2.基本内涵&#xff1a;对修改关闭&#xff0c;对扩展开放 3.要求&#xff1a;尽可能不修改源码而是增加新功能 例子 以spring5核心原理与30个类手写实战中的为例 package com.gupaoedu.vip.design.principle.openclose;/*** Crea…

拥抱智慧物流时代:数字孪生技术的应用与前景

概述 在数字经济全面推进的当下&#xff0c;物流行业正经历着前所未有的智能化升级。作为新一代信息技术的重要代表&#xff0c;数字孪生技术正悄然改变着物流的运作方式和决策模式。所谓数字孪生&#xff0c;是指在虚拟空间中创建与现实物流系统高度一致的数字模型&#xff0…

libnest2d-头文件分析-libnest2d.hpp-几何类型-策略类型-参数配置

libnest2d 库的主头文件&#xff0c;定义了一个用于 二维不规则形状自动排样&#xff08;Nesting&#xff09; 的C接口。以下是详细解析&#xff1a;1. 头文件结构 (1) 防止重复包含 #ifndef LIBNEST2D_HPP #define LIBNEST2D_HPP // ... #endif // LIBNEST2D_HPP确保头文件只被…

【Docker】部署Docker可视化管理面板Dpanel

一、DPanel 介绍 1.1 DPanel 简介 DPanel 是一款专为 Docker 设计的可视化管理面板&#xff0c;旨在降低容器、镜像及相关资源的管理门槛。通过简洁直观的图形化界面&#xff0c;即使是对 Docker 不熟悉的用户&#xff0c;也能轻松上手&#xff0c;实现容器化应用的高效部署与管…

GCC/G++ + Makefile/make 使用

一、gcc\g编译器 什么是gcc和g&#xff0c;它们的区别又是什么&#xff1f; gcc编译器是专门用来编译C语言的&#xff0c;而g编译器既可以编译C语言又可以用来编译C&#xff0c;但是主要还是用来编译C。 我们都知道代码形成可执行程序都是需要经过预处理、编译、汇编和链接这四…

重复文件查找工具:DataSecurity Plus 全面提升企业文件管理效率

企业日常运营经常会出现这样的场景&#xff1a;员工在文件传输、共享与备份过程中&#xff0c;因操作不当或系统设置问题&#xff0c;出现文件重复存储&#xff1b;跨部门协作时&#xff0c;相同的项目资料可能被多次保存&#xff1b;随着数据迁移与系统升级&#xff0c;重复文…

【软件架构】资源池架构设计中的三种主流模式

在资源池架构设计中&#xff0c;三种主流模式——集中式、分布式和混合式资源池——各有其独特的优势、劣势和适用场景。理解它们的区别对于设计高效、可靠和可扩展的系统至关重要。 下面是对这三种模式的详细分析和比较&#xff1a;集中式资源池 核心概念&#xff1a; 将所有计…

Java 类加载冲突

在某次线上部署过程中&#xff0c;我们遇到了一个十分诡异的问题&#xff1a;同样的应用&#xff0c;在 ext3 文件系统下运行正常&#xff0c;但部署到 ext4 文件系统下却出现了如下异常&#xff1a;The methods class, com.ctc.wstx.io.StreamBootstrapper, is available from…

VMware安装 统信UOS桌面专业版

前言 近年来&#xff0c;随着Linux发行版在开发者、企业环境中的应用逐渐增多&#xff0c;国产操作系统统信UOS&#xff08;基于Debian&#xff09;因其良好的图形化界面和本地化支持&#xff0c;成为不少用户体验Linux生态的选择之一。本文将以VMware Workstation Pro 17为例…