当前位置: 首页 > news >正文

【C语言:自定义类型(结构体、位段、共用体、枚举)】

文章目录

  • 1.结构体
    • 1.1什么是结构体
    • 1.2结构体类型声明
    • 1.3结构体变量的定义和初始化
    • 1.4结构体的访问
  • 2.结构体对齐
    • 2.1如何对齐
    • 2.2为什么存在内存对齐?
  • 3.结构体实现位段
    • 3.1什么是位段
    • 3.2位段的内存分配
    • 3.3位段的跨平台问题
    • 3.4位段的应用
    • 3.5位段使用注意事项
  • 4.联合体
    • 4.1联合体的声明
    • 4.2联合体的特点
    • 4.3联合体的大小
    • 4.4联合体与结构体的对比
  • 5.枚举
    • 5.1枚举类型的声明
    • 5.2枚举类型的优点

在这里插入图片描述

1.结构体

1.1什么是结构体

  • C语言已经提供了内置类型,如:char、short、int、long、float、double等,但是只有这些内置类型还是不够的,
  • 假设我想描述学生,描述⼀本书,这时单⼀的内置类型是不⾏的。描述⼀个学生需要名字、年龄、学号、身高、体重等;描述⼀本书需要作者、出版社、定价等。C语言为了解决这个问题,增加了结构体这种⾃定义的数据类型,让程序员可以⾃⼰创造适合的类型。
  • 结构体是⼀些值的集合,这些值称为成员变量结构体的每个成员可以是不同类型的变量,如:标量、数组、指针,甚⾄是其他结构体

1.2结构体类型声明

关键字:struct

struct stu   //stu 结构体的名字
{//以下是结构体的成员变量int age;char name[20];float score;//......
};  //分号不能丢

特殊声明方式:匿名结构体,即在声明结构体时不完全声明,省略了结构体的名字。

struct
{int a;char b;float c;
}x;

看下面的代码,这样做的结果时什么?

struct
{int a;char b;float c;
}x;
struct
{int a;char b;float c;
}a[20], * p;int main()
{p = &x;return 0;
}

在这里插入图片描述

编译器会把上⾯的两个声明当成完全不同的两个类型,所以是非法的。
匿名的结构体类型,如果没有对结构体类型重命名的话,基本上只能使⽤⼀次。

1.3结构体变量的定义和初始化

  1. 变量的定义
struct Point  
{int x;int y;
}p1; //声明类型的同时定义变量p1
struct Point p2; //定义结构体变量p2
  1. 变量的初始化
struct Point p3 = { 10, 20 };
struct Stu //类型声明
{char name[15];//名字int age; //年龄
};
struct Stu s1 = { "zhangsan", 20 };//按顺序初始化
struct Stu s2 = { .age = 20, .name = "lisi" };//指定顺序初始化
  1. 结构体嵌套、自引用
struct Node
{int data;struct Point p;//嵌套struct Node* next;//自引用
}n1 = { 10, {4,5}, NULL }; //结构体嵌套初始化
struct Node n2 = { 20, {5, 6}, NULL };//结构体嵌套初始化

1.4结构体的访问

结构体的访问有两种方式:

  • 直接访问:通过点操作符(.)访问
  • 间接访问:通过结构体指针访问,访问方式:结构体指针 -> 成员名

在这里插入图片描述

2.结构体对齐

在下面的代码中,char占1个字节,int占4个字节,那结构体的总大小就是5个字节,真的是这样嘛?

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

在这里插入图片描述

2.1如何对齐

要弄清结果为什么是8,我们就得了解结构体的对齐规则

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

  • 2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
    对齐数 = 编译器默认的⼀个对齐数 与 该成员变量大小的较小值

  • 3.VS 中默认的值为 8

  • 4.Linux中 gcc 没有默认对齐数,对齐数就是成员自身的大小。

  • 5.如果嵌套了结构体的情况,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处

  • 6.结构体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍

#pragma这个预处理指令,可以修改编译器的默认对齐数

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

到底是怎么对齐的呢?看下图
在这里插入图片描述

来练习几个吧

在这里插入图片描述

2.2为什么存在内存对齐?

大部分的参考资料都是这样说的:

  1. 平台原因 (移植原因):
    不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
  2. 性能原因:
    数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要⼀次访问。假设⼀个处理器总是从内存中取8个字节,则地址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对⻬成8的倍数,那么就可以⽤⼀个内存操作来读或者写值了。否则,我们可能需要执行两次内存访问,因为对象可能被分放在两个8字节内存块中。

总体来说:结构体的内存对⻬是拿空间来换取时间的做法。
因此,设计结构体的时候,我们既要满足对齐,⼜要节省空间,就要让占用空间小的成员尽量集中在⼀起。

3.结构体实现位段

3.1什么是位段

你听说过位段吗?是不是只听说过段位呀哈哈

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

  1. 位段的成员必须是 int、unsigned int 或signed int ,在C99中位段成员的类型也可以 选择其他类型,例如char。
  2. 位段的成员名后边有⼀个冒号和⼀个数字

位段的位其实指的就是二进制位,下面的A就是位段类型的

struct A
{int _a : 2;int _b : 5;int _c : 10;int _d : 30;
};
int main()
{printf("%d\n", sizeof(struct A));return 0;
}

2+5+10+30=47bit,一个字节是8个bit,那是不是6个字节就够了呢?
在这里插入图片描述
结果是8个字节。为什么是8个字节呢?----那是因为位段也存在对齐,位段的总大小也要对齐到自己最大成员变量的整数被。
注意:位段后的数字不可大于该数字本身的大小,否则就报错

3.2位段的内存分配

关于位段在内存中是如何存储的,C语言标准并未给出定义,下面我们就研究以下在VS中,位段是如何存储的。

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;
}

我们假设如果第一个字节中放不下了,就放在下一个字节中,第一个字节中剩余的比特位就舍弃,那么就是下面的结果:
在这里插入图片描述
vs中是不是这样存储的呢?看图我们知道,确实就是这样存的。
在这里插入图片描述

3.3位段的跨平台问题

  1. int 位段被当成有符号数还是⽆符号数是不确定的。
  2. 位段中最⼤位的数⽬不能确定。(16位机器最⼤16,32位机器最⼤32,写成27,在16位机器会出问题。
  3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
  4. 当⼀个结构包含两个位段,第⼆个位段成员⽐较⼤,⽆法容纳于第⼀个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的。

因此:跟结构相比,位段可以达到同样的效果,并且可以很好的节省空间,但是有跨平台的问题存在。

3.4位段的应用

下图是网络协议中,IP数据报的格式,我们可以看到其中很多的属性只需要⼏个bit位就能描述,这⾥使⽤位段,能够实现想要的效果,也节省了空间,这样⽹络传输的数据报大小也会较小⼀些,对网络的畅通是有帮助的。
在这里插入图片描述

3.5位段使用注意事项

  • 位段的⼏个成员共有同⼀个字节,这样有些成员的起始位置并不是某个字节的起始位置,那么这些位置处是没有地址的。内存中每个字节分配⼀个地址,⼀个字节内部的bit位是没有地址的
  • 所以不能对位段的成员使⽤&操作符,这样就不能使⽤scanf直接给位段的成员输⼊值,只能是先输⼊放在⼀个变量中,然后赋值给位段的成员。

在这里插入图片描述

4.联合体

4.1联合体的声明

  • 像结构体⼀样,联合体也是由⼀个或者多个成员构成,这些成员可以是不同的类型。
  • 但是编译器只为最⼤的成员分配⾜够的内存空间。联合体的特点是所有成员共⽤同⼀块内存空间。所以联合体也叫:共⽤体。
  • 给联合体其中⼀个成员赋值,其他成员的值也跟着变化。

在这里插入图片描述

4.2联合体的特点

  1. 所有变量公用同一块空间
  2. 改变一个成员,其它成员跟着变

在这里插入图片描述

4.3联合体的大小

  • 联合的大小⾄少是最⼤成员的大小。
  • 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对⻬数的整数倍

在这里插入图片描述

4.4联合体与结构体的对比

在这里插入图片描述
因此,使用联合体是比较节省空间的。

5.枚举

5.1枚举类型的声明

枚举枚举,顾名思义,就是一一列举。在生活中可以一 一列举出来的就可以使用枚举类型。例如

⼀周的星期⼀到星期⽇是有限的7天,可以⼀⼀列举
⽉份有12个⽉,也可以⼀⼀列举

枚举的关键字是enum,枚举成员用逗号隔开,最后一个成员不加逗号
在这里插入图片描述

  • 枚举的可能取值是常量,不能修改,因此我们也叫做枚举常量
  • 枚举类型的变量的值只能是枚举的可能取值

在这里插入图片描述

enum day
{Monday,		Tuesday,	Wednsdsday = 10,	Thursday,	Friday,		Saturday = 20,	Sunday		
};enum day d = Sunday;//使⽤枚举常量给枚举变量赋值

5.2枚举类型的优点

我们可以使用 #define 定义常量,为什么非要使用枚举?

枚举的优点:

  1. 增加代码的可读性和可维护性
  2. 和#define定义的标识符比较枚举有类型检查,更加严谨。
  3. 便于调试,预处理阶段会删除 #define 定义的符号
  4. 使用⽅便,⼀次可以定义多个常量
  5. 枚举常量是遵循作⽤域规则的,枚举声明在函数内,只能在函数内使⽤

相关文章:

【C语言:自定义类型(结构体、位段、共用体、枚举)】

文章目录 1.结构体1.1什么是结构体1.2结构体类型声明1.3结构体变量的定义和初始化1.4结构体的访问 2.结构体对齐2.1如何对齐2.2为什么存在内存对齐? 3.结构体实现位段3.1什么是位段3.2位段的内存分配3.3位段的跨平台问题3.4位段的应用3.5位段使用注意事项 4.联合体4…...

【1day】华天软件 OAworkFlowService接口SQL注入漏洞学习

注:该文章来自作者日常学习笔记,请勿利用文章内的相关技术从事非法测试,如因此产生的一切不良后果与作者无关。 目录 一、漏洞描述 二、影响版本 三、资产测绘 四、漏洞复现...

Oracle(2-11)RMAN Backups

文章目录 一、基础知识1、RMAN Backup Concepts RMAN备份概念2、RMAN Backup Modes RMAN备份的类型3、Backup File Types 备份文件类型4、RMAN Backup Destinations RMAN备份目标5、Backup Constraints 备份约束6、Recovery Manager Backups 恢复管理器备份7、Characteristics …...

使用docker搭建『Gitea』私有仓库

文章目录 一、安装 docker 环境1、移除以前的 docker 相关包2、配置yum源3、安装 docker4、启动 docker 二、安装 docker compose1、安装docker compose2、赋予下载的docker-compose执行权限 三、安装 gitea1. 创建工作目录2. 创建 Docker Compose 文件3. 启动 Gitea4. 访问 Gi…...

CopyOnWriteArrayList怎么用

什么是CopyOnWriteArrayListCopyOnWriteArrayList常用方法CopyOnWriteArrayList源码详解CopyOnWriteArrayList使用注意点CopyOnWriteArrayList存在的性能问题CopyOnWriteArrayList 使用实例基本应用实例并发应用实例 拓展写时复制 什么是CopyOnWriteArrayList CopyOnWriteArra…...

旋转设备状态监测与预测性维护:提高设备可靠性的关键

在工业领域的各个行业中,旋转设备都扮演着重要的角色。为了确保设备的可靠运行和预防潜在的故障,旋转设备状态监测及预测性维护变得至关重要。本文将介绍一些常见的旋转设备状态监测方法,并探讨如何利用这些方法来实施预测性维护,…...

类和对象——(7)this指针

归纳编程学习的感悟, 记录奋斗路上的点滴, 希望能帮到一样刻苦的你! 如有不足欢迎指正! 共同学习交流! 🌎欢迎各位→点赞 👍 收藏⭐ 留言​📝 人生就像骑单车,想保持平衡…...

回溯算法题型分类

题型一:排列、组合、子集相关问题 提示:这部分练习可以帮助我们熟悉「回溯算法」的一些概念和通用的解题思路。解题的步骤是:先画图,再编码。去思考可以剪枝的条件, 为什么有的时候用 used 数组,有的时候设…...

ApplicationRunner 类

优质博文:IT-BLOG-CN 在开发中可能会有这样的情景。需要在容器启动的时候执行一些内容。比如读取配置文件,数据库连接之类的。SpringBoot给我们提供了两个接口来帮助我们实现这种需求。这两个接口分别为CommandLineRunner和ApplicationRunner。他们的执…...

QT中的 容器(container)-大全

一、介绍 Qt库提供了一套通用的基于模板的容器类&#xff0c;可以用这些类存储指定类型的项。比如&#xff0c;你需要一个大小可变的QString的数组&#xff0c;则使用QVector<QString>。 这些容器类比STL&#xff08;C标准模板库&#xff09;容器设计得更轻量、更安全并…...

Docker配置镜像加速器

Ubuntu 安装&#xff0f;升级Docker客户端 推荐安装1.10.0以上版本的Docker客户端&#xff0c;参考文档docker-ce配置镜像加速器 针对Docker客户端版本大于 1.10.0 的用户 您可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器 sudo mkdir -p /etc/docker sudo t…...

飞致云1panel + 雷池WAF

可能有许多人都有这个需求&#xff1a;为自己的个人站点套上WAF&#xff0c;增加安全性&#xff0c;本文将介绍如何将1panel面板深度结合长亭雷池防火墙&#xff0c;实现为个人站点套上WAF并且自动续签ssl证书。 前提条件&#xff1a; 服务器IP已绑定域名 完整的1panel环境 …...

策略梯度简明教程

策略梯度方法 (PG&#xff1a;Policy Gradient) 是强化学习 (RL&#xff1a;Reinforcement Learning) 中常用的算法。 1、从库里的本能开始 PG的原理很简单&#xff1a;我们观察&#xff0c;然后行动。人类根据观察采取行动。 引用斯蒂芬库里的一句话&#xff1a; 你必须依靠…...

鸿蒙原生应用/元服务开发-利用picker选择器来多选相册图片

前言 在之前的时候&#xff0c;测试一个应用进入相册选择图片demo&#xff0c;利用了startAbilityForResult()方法&#xff0c;启动相对应的Ability来完成效果&#xff0c;但是这种方法有限制&#xff0c;一次只能获取一张图片&#xff0c;在完成某些功能测试的时候就很不方便。…...

java:封装统一的响应体code、data、msg、paging

背景 我们在写接口的时候一般不会直接返回给前端数据&#xff0c;而是会有响应体&#xff0c;比如 code、data、msg&#xff0c;这样就有一个统一的结构方便前端处理&#xff0c;那么今天就来封装一个统一的响应体 封装基本响应体 1、在 config 包里新建 ApiResponse.java …...

leetcode算法之栈

目录 1.删除字符串中的所有相邻重复项2.比较含退格的字符串3.基本计算器II4.字符串解码5.验证栈序列 1.删除字符串中的所有相邻重复项 删除字符串中的所有相邻重复项 class Solution { public:string removeDuplicates(string s) {string ret;//使用数组模拟栈操作for(auto …...

电脑上mp4视频文件无缩略图怎么办

前言&#xff1a;有时候电脑重装后电脑上的mp4视频文件无缩略图&#xff0c;视频文件数量比较多的时候查找比较麻烦 以下方法亲测有效&#xff1a; 1、下载MediaPreview软件 2、软件链接地址&#xff1a;https://pan.baidu.com/s/1bzVJpmcHyGxXNjnzltojtQ?pwdpma0 提取码&…...

【Centos8】配置网络镜像源

文章目录 配置 yum 源配置网络 yum 源备份下载阿里 centos-base.repo 到 /etc/yum.repos.d/安装 EPEL 源测试安装 配置 yum 源 # 检查是否安装了 yum rpm -qa|grep yum# 查看本地已安装的所有软件包 yum list installed# 查看软件包安装位置 # 查看某个东西的软件包 rpm -qa|g…...

深入学习Synchronized各种使用方法

文章目录 前言一、synchronized关键字通用在下面四个地方&#xff1a;1.1synchronized修饰实例方法1.2synchronized修饰静态方法&#xff1a;1.3synchronized修饰实例方法的代码块1.4synchronized修饰静态方法的代码块2.读入数据 二.Sychronized关键特性2.1互斥2.2 刷新内存2.3…...

【idea】设置鼠标滚轮控制缩放大小

1、点击file 选择Setting 2、点击Editor 下面的 General 3、勾选 Mouse Control 下面的 Change font size with CtrlMouse Wheel in 4、点级apply 5、按 ctrl键 鼠标滚轮缩放字体的大小...

合并两个有序数组(leetcode_刷题1)

目录 题目&#xff1a;合并两个有序数组 题目分析方向1&#xff1a; 题目分析方向2&#xff1a; 题目&#xff1a;合并两个有序数组 题目要求&#xff1a; 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分别表示 nums…...

麒麟linux将图片批量生成PDF的方法

笔者手里有一批国产linu系统&#xff0c;目前开始用在日常的工作生产环境中&#xff0c;我这个老程序猿勉为其难的充当运维的或网管的角色。 国产linux系统常见的为麒麟Linux&#xff0c;统信UOS等&#xff0c;基本都是基于debian再开发的linux。 问题描述&#xff1a; wind…...

Linux——vim编辑文件时——.swp文件解决方案

test.cpp样例 当我们vim test.cpp进入编辑文件。 却忘记了保存退出 再次进入就会出现一下画面 当你摁下Enter键位 出现以下几个选项 O——是只读不写 E——是正常打开文件但不会载入磁盘内容 R——覆盖——是加载存储磁盘的文件(当我们忘记保存时&#xff0c;系统会自动帮我…...

【Maven】清理 maven 仓库

初始情况下&#xff0c;我们的本地仓库是没有任何jar包的&#xff0c;此时会从私服去下载&#xff08;如果没有配置&#xff0c;就直接从中央仓库去下载&#xff09;。 可能由于网络的原因&#xff0c;jar包下载不完全&#xff0c;这些不完整的jar包都是以lastUpdated结尾。此…...

APOLLO自动驾驶技术沙龙:未来已来,共创智能交通新时代

在这次Apollo会议上&#xff0c;我深刻地感受到了人工智能自动驾驶技术领域的最新进展和未来趋势。作为一名从事软件开发工作的人员&#xff0c;我深感荣幸能够参加这次盛会。 前言 本次活动是百度Apollo社区工程师齐聚首钢Park&#xff0c;带来现场实操与技术分享。主要围绕Ap…...

Java面试题12

1.redis 怎么实现分布式锁&#xff1f; Redis可以通过以下方式实现分布式锁&#xff1a; 使用RedLock算法&#xff1a;多个Redis节点组合使用&#xff0c;通过竞争锁来达到分布式锁的效果。使用SETNX命令&#xff1a;利用SETNX&#xff08;SET if Not eXists&#xff09;命令…...

ubuntu上创建服务启动python脚本

场景 最近在使用ubuntu服务器部署MySQL和同步数据&#xff0c;同步数据使用的是python&#xff0c;但是我不能直接操作服务器&#xff0c;只能通过Xshell远程访问服务器&#xff0c;但是启动python脚本的时候如果关掉xshell会停止Python脚本&#xff0c;所以如果要让python脚本…...

51单片机制作数字频率计

文章目录 简介设计思路工作原理Proteus软件仿真软件程序实验现象测量误差和范围总结 简介 数字频率计是能实现对周期性变化信号频率测量的仪器。传统的频率计通常是用很多的逻辑电路和时序电路来实现的&#xff0c;这种电路一般运行较慢&#xff0c;而且测量频率的范围较小。这…...

java中强引用、软引用、弱引用、虚引用的区别是什么?

Java中的引用类型主要分为强引用、软引用、弱引用和虚引用&#xff0c;它们之间的区别主要体现在垃圾回收的行为上。 强引用&#xff08;Strong Reference&#xff09;&#xff1a;这是使用最普遍和默认的引用类型。如果一个对象具有强引用&#xff0c;那么垃圾回收器就永远不会…...

springboot -事务管理

事务 概念 事务是一组操作的集合&#xff0c;它是一个不可分割的工作单位&#xff0c;这些操作要么同时成功&#xff0c;要么同时失败。 操作 开启事务&#xff1a; start transaction / begin提交事务&#xff1a;commit回滚事务&#xff1a; rollback 注解 Transactional …...

微软 开源 wordpress/网络运营培训

基于PyQt5 Python3.7 OpenCV实现的人脸识别身份认证系统&#xff0c;附源码。 技术选型 PyQt5 Python3.7 OpenCV 功能概述 实现人员注册,信息修改,人脸识别获取相关信息 人员信息通过序列化存储在datafile.txt文件中 haarcascade_frontalface_default.xml是OpenCV中自…...

企业网站建设合同(一)/杭州网站seo

文章目录数据集格式基于线性回归sigmoid实现二分类的表达式链式法则求导链式表达式求解∂l∂oj^\frac{\partial l}{\partial \hat{o_j}}∂oj​^​∂l​求解∂oj∂wij\frac{\partial o_j}{\partial w_{ij}}∂wij​∂oj​​求解∂oj∂bj\frac{\partial o_j}{\partial b_j}∂bj​∂…...

建设网站 翻译/网站seo关键词设置

最近负责的邮箱系统项目中有一个这样的需求&#xff1a;提供一个接口给业务层&#xff0c;可以通过邮箱查询到该用户的未读邮件个数。 之前的方案是通过查看用户目录下.INBOX/new目录中的文件个数&#xff0c;但是这个方法不准确&#xff0c;当有用户连接到邮箱服务器时&#x…...

建个简单的网站/网站推广策略有哪些

参考&#xff1a; 技术解析&#xff5c;Doris Connector 结合 Flink CDC 实现 MySQL 分库分表 Exactly Once 精准接入-阿里云开发者社区 逻辑图&#xff1a; 1. Flink环境&#xff1a; https://flink.apache.org/zh/ 下载flink-1.15.1 wget https://dlcdn.apache.org/flink…...

手机营销型网站建设/手游代理加盟哪个平台最强大

我正在为数据库实现一个漂亮的基本搜索引擎&#xff0c;用户可能会在其中包含不同类型的信息。搜索本身由几个联合组成&#xff0c;选择结果总是合并到3列中。然而&#xff0c;返回的数据正在从不同的表中获取。每个查询使用$ term进行匹配&#xff0c;我将其绑定到“&#xff…...

网站建设电销异议处理话术/优化关键词快速排名

齐博提取出来的 判断是否为手机浏览器的函数index的代码为if($IsMob){header("location:wapindex.php");exit;}common.inc.php 里面关于$IsMob的定义为$IsMobis_mobile();function.inc.php 中提取函数//检查是否为手机访问function is_mobile(){$regex_match"/(…...