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

C/C++之自定义类型(结构体,位段,联合体,枚举)详解

个人主页:点我进入主页

专栏分类:C语言初阶      C语言程序设计————KTV       C语言小游戏     C语言进阶

C语言刷题

欢迎大家点赞,评论,收藏。

一起努力,一起奔赴大厂。

目录

个人主页:点我进入主页

 

1.前言

2.结构体

2.1结构体声明

2.2结构体初始化

2.3结构体的自引用

2,4结构体的内存对齐

 3.位段

3.1什么是位段

3.2位段的内存分配

3.3位段的跨平台性

4.枚举 

4.1枚举声明

4.2枚举的优点

4.3枚举的使用

5.联合体

5,1联合体的声明

5.2联合体的大小

5.3联合体的使用


 

1.前言

        随着我们深入学习C语言,我们发现单纯的int,char,double,float类型已经不能满足我们的需要了,那C语言是否还有其他的类型呢,事实上还有一类那就是结构体,结构体是我们自己创造的一种类型,它可以包含C语言的所有类型,结构体是什么呢?结构体如何创建?结构体如何初始化?等问题我会给大家详细解析

2.结构体

2.1结构体声明

        对于结构体如何声明,例如我们想创建一个关于学生的信息,包括名字和学号我们可以如下操作:

struct student{int num;cahr name[50];
};

2.2结构体初始化

        对于结构体的初始化我们可以看如下代码:

#include <stdio.h>
struct student {int num;char name[50];
};
int main()
{struct student s[3] = { {1,"zhansan"},{2,"lisi"} };int i;for (i = 0; i < 2; i++){printf("%d %s\n", s[i].num, s[i].name);}return 0;
}

        对于结构体的访问我们需要用到“.”或者"->"进行访问“.”就是让面的操作对于“->”就是传址也就是指针我们可以进行如下操作,代码如下:

#include <stdio.h>
struct student {int num;char name[50];
};
int main()
{struct student s[3] = { {1,"zhansan"},{2,"lisi"} },*p=s;int i;for (i = 0; i < 2; i++){printf("%d %s\n", p->num ,p->name );p++;}return 0;
}

2.3结构体的自引用

        对于结构体,还有一种操作就是结构体的自引用,我们还可以理解为结构体嵌套结构体具体的代码如下:

struct student {int num;char name[50];
};
struct Std {struct student std[3];int gard;
};

        对于striuct Std类型的变量初始化和struct student类型的相似只是多次操作即可例如s.std[0].num=1;

2,4结构体的内存对齐

        结构体中有一个很有意思的现象,代码如下:

#include <stdio.h>
struct student1 {char ch1;char ch2;int i;
};
struct student2 {char ch1;int i;char ch2;
};
int main()
{printf("%d\n", sizeof(struct student1));printf("%d\n", sizeof(struct student2));
}

代码输出的结果为

f62c784685694e7c95111a7c38acef0a.png

        问什么会这样呢?我们一般的理解是char占用1个字节,int占4个字节,共占6个字节,这就和结构体的内存对齐有关了 ,首先得掌握结构体的对齐规则:

1. 第一个成员在与结构体变量偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。VS中默认的值为8
3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
为什么存在内存对齐?

我们可以理解为第一个占0位置,对齐数就是编译器的默认值和成员大小的较小值,偏移量的初始位置为对齐数的倍数,最后所占的字节为最大成员的倍数。 

例如我们第一个结构体进行画图讲解:

 ce1799fbd4da4589b25022f8d8580b5f.png

         ch1占0的位置,ch2的对齐数是1占1的位置,num的对齐数是4占4的位置,共占8个8是4的倍数故占8个字节。

对于对齐数的默认值我们可以用#pragma pack()进行修改,例如#pragma pack(8);

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

1. 平台原因(移植原因):
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特
定类型的数据,否则抛出硬件异常。
2. 性能原因:
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访
问。

总体来说:

结构体的内存对齐是拿空间来换取时间的做法。
那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到:
让占用空间小的成员尽量集中在一起。

 3.位段

3.1什么是位段

        位段和结构体类似,它的成员是int,unsigned int ,signed int,它的形式是类型 +变量名+: 字节数,它的详细代码可以理解为:

struct num {int a : 2;int b : 3;int i : 30;
};

3.2位段的内存分配

1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。

 例如如下代码的内存分配:

#include <stdio.h>
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;
}

我们可以进行画图理解:

        由于位段的不确定性所以我我们在一个字节中不知道是占高位还是低位,我们正常思维是占低位,在占低位时可以理解为

0f0d17f8581c4e8a85d6bf95ce61d081.png

        这样第一个字节为01100010为62,第二个字节为00000011为03,第三个字节为00000100为04,真实的储存是不是我们理解的呢?我们进入调试看一看内存

571504a1a14f4bc383e6a33a4b49827d.png

        于是这样就形成了位段,对于位段占几个字节我们可以利用sizeof()进行操作得到它占用几个字节 。

3.3位段的跨平台性

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

位段在信息传输时有很重要i的作用,在这里不做讲解。

4.枚举 

4.1枚举声明

enum s {blue,red,back
};

        枚举和#define一样在上面的代码中blue相当于#define blue 0,red相当于 #define red 1,back相当于#define back 2。难道只能从0开始吗?显然是不可能的,我们应该如何修改?如下:

enum s {blue=3,red=2,back=10
};

4.2枚举的优点

我们可以使用 #define 定义常量,为什么非要使用枚举?
枚举的优点:
1. 增加代码的可读性和可维护性
2. 和#define定义的标识符比较枚举有类型检查,更加严谨。
3. 防止了命名污染(封装)
4. 便于调试
5. 使用方便,一次可以定义多个常量

4.3枚举的使用

枚举的使用主要就是switch case语句中例如

 

enum s {blue,red,back
};
int main()
{int a = 1;switch (a){case blue:; break;case red:; break;case back:; break;}return 0;
}

5.联合体

5,1联合体的声明

联合体声明如下:

union Un1
{char c[5];int i;
};

5.2联合体的大小

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

联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。

对于联合体的成员共同占用一个空间,我们可以做一个测试,代码如下:

#include <stdio.h>
union Un1
{char c[5];int i;
};int main()
{union Un1 u1;printf("%p\n", &u1.c);printf("%p\n", &u1.i);printf("%p\n", &u1);
}

我们运行结果如下:

cb3aa2523a2c448a981860bdaf716658.png

因此我们可以得到联合体存储的方式

6a359a82e91c4669a91410d2317d0e9b.png

 对于如何计算联合体的大小,我们可以看一下代码:

#include <stdio.h>
union Un1
{char c[5];int i;
};
union Un2
{short c[7];int i;
};
int main()
{printf("%d\n", sizeof(union Un1));printf("%d\n", sizeof(union Un2));
}

对于Un1我们可以画成a726c0b001d242fd9f0614e7d9ae6a79.png

        对于c占5个字节,i占4个字节,但是c是char类型是1个字节,成员最大的为4,由于需要占最大成员的倍数 故占8个字节。Un2也是同样的操作,short占2个字节,共14个字节,int占4个字节,共占用16个字节。

5.3联合体的使用

        我们知道联合体是一种节省空间存储方式,我们可以把它用在多个不共同使用的多i个结构体创建上大致可以理解为

struct num{

        union u1{

               结构体1;

               结构体2;

                ......

        };

};

今天的内容就结束了,欢迎大家来三连。 

 

相关文章:

C/C++之自定义类型(结构体,位段,联合体,枚举)详解

个人主页&#xff1a;点我进入主页 专栏分类&#xff1a;C语言初阶 C语言程序设计————KTV C语言小游戏 C语言进阶 C语言刷题 欢迎大家点赞&#xff0c;评论&#xff0c;收藏。 一起努力&#xff0c;一起奔赴大厂。 目录 个人主页&#xff1a;点我进入主页 …...

HBase 表如何按照某表字段排序后顺序存储的方法?

首先需要明白HBase表的排序规则&#xff1a; &#xff08;1&#xff09;rowkey排序&#xff08;字典排序&#xff09;——升序 &#xff08;2&#xff09;Column排序&#xff08;字典排序&#xff09;——升序 &#xff08;3&#xff09;时间戳排序——降序 rowkey 字典序排序…...

webrtc用clang编译支持h264,支持msvc调用库

webrtc遇到困扰&#xff1a; 如果msvc编译&#xff0c;ffmpeg编译失败&#xff0c;需要替换ffmpeg库。如果用clang编译&#xff0c;vs或qt调用dll又存在崩溃。 经过反复尝试找到解决方法&#xff1a; 一、编译 1、编译参数 //我得环境配置 set DEPOT_TOOLS_UPDATE0 set DEP…...

迁移学习是什么?

迁移学习&#xff08;Transfer Learning&#xff09;是一种机器学习方法&#xff0c;它的主要思想是将已经在一个任务上学到的知识迁移到另一个相关或不相关的任务上&#xff0c;以提高目标任务的性能。迁移学习的核心概念是&#xff0c;模型可以通过先前学到的知识来更好地解决…...

哈希的应用--位图和布隆过滤器

哈希的应用--位图和布隆过滤器 位图1. 位图概念2. 位图在实际中的应用3. 位图相似应用给定100亿个整数&#xff0c;如何找到只出现一次的整数&#xff1f;1个文件100亿int&#xff0c;1G内存&#xff0c;如何找到不超过2次的所有整数 布隆过滤器1. 布隆过滤器的提出2. 布隆过滤…...

mac M2芯片在使用Android studio 编译问题bad cpu type in executable android

由于mac的intel芯片的一些指令集没有同步在M1 M2芯片上所以需要做兼容 打开控制台&#xff08;通过访达 - 应用程序 - 实用工具 - 终端 &#xff09; 输入 softwareupdate --install-rosetta 之后在输入 A 就可以了。 原产考地址&#xff1a;硬核&#xff01;在 M1 芯…...

M4Singer ubuntu 22.04 4060ti16g ModuleNotFoundError: No module named ‘gradio‘

故障 Traceback (most recent call last): File "inference/m4singer/gradio/infer.py", line 4, in <module> import gradio as gr ModuleNotFoundError: No module named gradio 解决 (venv3712) (base) yeqiangyeqiang-Default-string:~/Downloa…...

postman 密码rsa加密登录-2加密密码

上一篇讲了获取公钥&#xff0c;将环境准备好之后&#xff0c;在登录接口的Pre-request Scrip 里&#xff0c;使用公钥进行加密后在正常登录。本文采用的方案是使用第三方模块forge.js来实现加密。 1、环境准备好&#xff0c;系统git 和node都OK。下载forge.js git clone htt…...

如何去图片水印?这些方法解决你的问题

当我们希望更新自己的头像时&#xff0c;经常会发现网上有许多精彩的图片&#xff0c;但它们通常带有水印&#xff0c;使我们无法轻松使用这些照片。这个情况大家应该都有遇到过吧&#xff1f;那么&#xff0c;如何去除图片上的水印呢&#xff1f;接下来&#xff0c;我们将分享…...

Qt通过正则表达式筛选出字符串中的手机号

需求 用户需要聊天记录中含有11位的手机号码进行提醒的功能&#xff0c;所以需要在收到聊天消息后匹配查看是否存在手机号。如果找到然后提醒。 分析 主要的需求可以拆分为两点&#xff1a; 筛选出字符串里面的数字字符。通过正则匹配数字字符是否是11位手机号码。 一开始没…...

【Pytorch】深度学习之数据读取

数据读入流程 使用DatasetDataLoader完成Pytorch中数据读入 Dataset定义数据格式和数据变换形式 DataLoader用iterative的方式不断读入批次数据&#xff0c;实现将数据集分为小批量进行训练 使用PyTorch自带数据集 使用Dataset完成数据格式和数据变换的定义 import torch fro…...

Maven教程

Maven介绍 Maven 环境配置 Maven Pom Maven 构建生命周期 Maven 构建配置文件 Maven 插件 Maven 仓库 Maven 构建Java项目 Maven 构建&项目测试 Maven 引入外部依赖 Maven 项目模板 Maven 项目文档 Maven 快照(SNAPSHOT) Maven 自动化构建 Maven 依…...

一篇带你看懂异步:promise、async await

在前端开发中&#xff0c;特别是使用Vue.js框架时&#xff0c;Promises&#xff08;承诺&#xff09;和resolve是与异步操作相关的重要概念。让我来解释一下它们的含义和如何在Vue.js中使用它们。 一、Promise 1. Promise&#xff08;承诺&#xff09;: Promise是一种处理异…...

RocketMQ快速实战以及集群架构详解

文章目录 一、MQ简介二、RocketMQ产品特点RocketMQ介绍RocketMQ特点 三、RocketMQ快速实战快速实现消息收发命令行快速实现消息收发搭建Maven客户端项目 搭建RocketMQ可视化管理服务 四、升级分布式集群五、升级高可用集群六、总结RocketMQ的运行架构七、理解RocketMQ的消息模型…...

京东运营数据分析:2023年8月京东饮料行业品牌销售排行榜

鲸参谋监测的京东平台8月份饮料市场销售数据已出炉&#xff01; 8月份&#xff0c;饮料市场整体销售下滑。根据鲸参谋电商数据分析平台的相关数据显示&#xff0c;今年8月&#xff0c;京东平台饮料市场的总销量将近820万&#xff0c;环比下滑约8%&#xff0c;同比下滑约20%&am…...

ES6之函数的扩展二

ES6之函数的扩展一 传送门 9.3 函数length属性 函数的length属性&#xff0c;不包含rest参数 console.log((function (a) {}).length) // 1 console.log((function (...a) {}).length) // 0 console.log((function (a1,b,...a) {}).length) // 210&#xff1a;严格模式 在 …...

Ubuntu-Ports更新源 ARM64更新源

Ubuntu-Ports更新源 Ubuntu ARM64更新源 简介&#xff1a; Arm64&#xff0c;Armhf等平台的Ubuntu软件仓库。 Ubuntu-Ports国内镜像源 华为镜像Ubuntu-Ports 阿里云镜像Ubuntu-Ports 清华大学镜像Ubuntu-Ports 改用清华大学镜像更新源 Ubuntu 的软件源配置文件是 /etc/ap…...

渗透测试怎么入门?(超详细解读)

1. 什么是渗透测试 渗透测试就是模拟真实黑客的攻击手法对目标网站或主机进行全面的安全评估&#xff0c;与黑客攻击不一样的是&#xff0c;渗透测试的目的是尽可能多地发现安全漏洞&#xff0c;而真实黑客攻击只要发现一处入侵点即可以进入目标系统。 一名优秀的渗透测试工程…...

MS31804四通道低边驱动器可pin对pin兼容DRV8804

MS31804TE 是一个具有过流保护功能的四通道低边驱动器。MS31804TE 内置钳位二极管&#xff0c;用来钳制由电感负载续流产生的电压。MS31804TE 可以驱动单极步进电机、直流电机、继电器、螺线管或者其它负载。 散热良好的情况下&#xff0c;MS31804TE 可以提供每个通道最高 2A 的…...

Fastadmin 子级菜单展开合并,分类父级归纳

这里踩过一个坑&#xff0c;fastadmin默认的展开合并预定义处理的变量是pid。 所以建表时父级id需要是pid&#xff1b; 当然不是pid也没关系&#xff0c;这里以cat_id为例&#xff0c;多加一步处理一样能实现。 废话少说上代码&#xff1a; 首先在控制器&#xff0c; 引用…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能

1. 开发环境准备 ​​安装DevEco Studio 3.1​​&#xff1a; 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK ​​项目配置​​&#xff1a; // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程

STM32F1 本教程使用零知标准板&#xff08;STM32F103RBT6&#xff09;通过I2C驱动ICM20948九轴传感器&#xff0c;实现姿态解算&#xff0c;并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化&#xff0c;适合嵌入式及物联网开发者。在基础驱动上新增…...

nnUNet V2修改网络——暴力替换网络为UNet++

更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...

MySQL的pymysql操作

本章是MySQL的最后一章&#xff0c;MySQL到此完结&#xff0c;下一站Hadoop&#xff01;&#xff01;&#xff01; 这章很简单&#xff0c;完整代码在最后&#xff0c;详细讲解之前python课程里面也有&#xff0c;感兴趣的可以往前找一下 一、查询操作 我们需要打开pycharm …...

Modbus RTU与Modbus TCP详解指南

目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...

Java中栈的多种实现类详解

Java中栈的多种实现类详解&#xff1a;Stack、LinkedList与ArrayDeque全方位对比 前言一、Stack类——Java最早的栈实现1.1 Stack类简介1.2 常用方法1.3 优缺点分析 二、LinkedList类——灵活的双端链表2.1 LinkedList类简介2.2 常用方法2.3 优缺点分析 三、ArrayDeque类——高…...

Excel 怎么让透视表以正常Excel表格形式显示

目录 1、创建数据透视表 2、设计 》报表布局 》以表格形式显示 3、设计 》分类汇总 》不显示分类汇总 1、创建数据透视表 2、设计 》报表布局 》以表格形式显示 3、设计 》分类汇总 》不显示分类汇总...