【C语言】自定义类型(结构体、枚举、联合的详解)下

写在前面

书接上回:【C语言】自定义类型(结构体、枚举、联合的详解)上
在上中,不才独篇撰写了结构体的具体细节,本篇笔记主要是把剩下的自定义类型全部展示。

文章目录

  • 写在前面
  • 二、位段
    • 2.1、位段的定义
    • 2.2、位段占用空间的计算
    • 2.3、位段的跨平台问题
    • 2.4、位段的应用
  • 三、枚举
    • 3.1、枚举类型的定义
    • 3.2枚举的使用
    • 3.3、枚举的优点
  • 四、联合(共用体)
    • 4.1联合类型的定义
    • 4.2、联合大小的计算


二、位段

位段的定义方式和结构体相差无几,但是有几处不同

  1. 位段成员可以根据程序猿的需要来自定义位段成员的大小。
  2. 位段的成员必须是int、unsigned int 或signed int
  3. 位段的成员名后边有一个冒号和一个数字。
  4. 位段的成员名后边的数字,代表着这个成员占用多少个比特位。

2.1、位段的定义

举个栗子:

struct A
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};
  • 位段的类型成员为了与结构体成员等自定义类型成员有所区分,所以在位段成员前面增加下划线来表示此变量为位段成员。
  • _a成员 后面的数组代表着:占用struct A位段空间中的2个比特位。
  • _b成员 后面的数组代表着:占用struct A位段空间中的5个比特位。
  • _c成员 后面的数组代表着:占用struct A位段空间中的10个比特位。
  • _d成员 后面的数组代表着:占用struct A位段空间中的30个比特位。

2.2、位段占用空间的计算

位段的空间占用情况是C语言标准未定义的,所以注重移植性的程序应该谨慎使用位段

本次测试的环境是VS2013 x86环境
我们先使用sizeof操作符计算上面栗子中struct A的大小
在这里插入图片描述
结果为8,即占用了64个比特位,但是我们在struct A中我们只定义了47个比特位,为什么为造成在内存中申请了64个比特位呢,我们需要知道位段的内存分配。

1.位段的成员可以是int unsigned int signed int或者是char(属于整形家族)类型
2.位段的空间上是按照需要以4个字节int)或者1个字节char)的方式来开辟的。根据位段内部定义的类型来开辟 。.但是类型空间内部的使用顺序是C语言标志未定义的,在前个字节中,剩下未使用的比特位是否使用也是C语言标准未定义的
3.位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。

注意:每个平台对位段的处理可能都不一样,就连VS2013和VS2022都是不相同的。
vs2022是不忽略前面空出的比特位的。

根据上面内存分配的定义,目前使用VS2013环境

  • struct A中的成员变量是int类型,所以在内存中首先开辟4个字节,在位段中,我们是先使用地址的字节后使用高地址的字节的。在比特位中,也是先使用低位再使用高位,那_a先占用2个比特位,_b再占用5个比特位。如下图
    在这里插入图片描述
  • 此时,_a与_b都已在内存中找到合适的位置存储,接下到_c占用空间,在第一个字节中,还剩下一个比特位没有被占用,但是为了更高的效率,我们是不使用那个字节的。
  • 浪费一个字节往高地址的空白字节中占用比特位,在第二个字节中,只有8个比特位,不足存放10个比特位,就继续向后寻找,直到有足够的比特位。如下图在这里插入图片描述

-此时,_a、_b与_c 都已在内存中找到合适的位置存储,接下到_d占用空间 但是_d需要30个比特位,卸载只剩下8个可以用比特位,就需要继续开辟四个字节,如下图在这里插入图片描述

  • 在开辟4个字节后,存放_d成员后,得到下图。在这里插入图片描述

在得到了每个成员变量占用对应的位置后,我们就开始赋值操作。在内存中是以二进制进行存储的,所以我们需要把所有的10进制数字先转为二进制数组。如下图在这里插入图片描述

因为_a只能存储2个比特位,所以会发生截断,只能保存最低位的2个比特位。如下图
在这里插入图片描述

随后_b的值存入内存,即12的二进制为:1100。_b可以存放5个字节,即可以全部存入。如下图
在这里插入图片描述

_c的值存入内存,即20的二进制为:0001 0100。_c可以存放20个字节,即可以全部存入。如下图在这里插入图片描述

同理,_d的值存入内存可得下图:在这里插入图片描述

整理上图,我们可以得到struct A内存的具体值:在这里插入图片描述

为了验证我们上面的准确性,我们把得到的值翻译成16进制后,与程序对比来验证准确性。

  • 0110 0010 => 32
  • 0000 0000 => 00
  • 0001 0100 => 14
  • 0000 0000 => 00
  • 0000 1111 => 0F
  • 0110 0011 => 63
  • 1110 0011 => E3
  • 0000 0000 => 00

2.3、位段的跨平台问题

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

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

2.4、位段的应用

位段一般使用在网络传输中,在网络传输层中,需要存储大量的表示(如下图),如果每个表示都使用int类型来编写,每个类型都占用4个字节就会导致大量的无用字节占用通道,导致效率下降,我们使用位段就可以完美解决这个问题。
在这里插入图片描述

三、枚举

枚举顾名思义就是一一列举。
把可能的取值一一列举。
比如我们现实生活中:

一周的星期一到星期日是有限的7天,可以一一列举。
性别有:男、女、保密,也可以一一列举。
月份有12个月,也可以一一列举

3.1、枚举类型的定义

enum Day//星期
{
	Mon,
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun
};
  • 枚举标识符enumDay是枚举标签,与结构体相似
  • 枚举成员称为:枚举常量。每个枚举常量之间需要使用逗号,分隔,不能使用分号
  • 每个枚举创建大括号后都需要加上分号
  • 枚举类型是: 枚举标识符 + 枚举标签。上面例子中的枚举类型为:enum Day。
  • 每个枚举常量都是默认有值的,默认从0开始,依次递增1,也可以在初始化时候赋初值。
  • 枚举常量是常量,不能在程序运行时被赋值和修改本身。只能在初始化时候赋初值(如下),赋初值只能是整形常量表达式。
enum Color//颜色
{
 RED=1,
 GREEN=2,
 BLUE=4,
 yellow
 };

enum Color枚举中:

  • RED枚举常量赋了初值为:1
  • GREEN枚举常量赋了初值为:2
  • BULE枚举常量赋了初值为:4
  • yellow没有赋初值,则递增1,即为:5

3.2枚举的使用

enum Color//颜色
{
	RED = 1,
	GREEN = 2,
	BLUE = 4,
	yellow
};
int main() {
	enum Color clr1 = GREEN;//只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。
	enum Color clr2 = yellow;
	printf("GREEN = %d\n", clr1);
	printf("yellow = %d\n", clr2);
	int n1 = (int)GREEN;
	printf("n1 = %d\n", n1);
	return 0;
}

若修改枚举常量则会报错
在这里插入图片描述

enum Color//颜色
{
	RED = 1,
	GREEN = 2,
	BLUE = 4,
	yellow
};
int main() {
	enum Color clr = GREEN;//只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。
	clr = 5;
	printf("%d ", clr);
	return 0;
}

在这里插入图片描述

3.3、枚举的优点

枚举的优点:

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

四、联合(共用体)

4.1联合类型的定义

联合也是一种特殊的自定义类型 这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块
空间(所以联合也叫共用体)。 比如:

//联合类型的声明
union Un
{
	char c;
	int i;
};
int main() {
	//联合变量的定义
	union Un un;
	//计算连个变量的大小
	printf("%d\n", sizeof(un));
	return 0;
}
  • 计算出的大小是4个字节,说明在联合类型中我们虽然同时有char类型和int类型,但是这两个类型在空间中只占用最大类型的空间,内存分布图如下图:在这里插入图片描述

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

我们打印地址证明内存图正确(上图)

union Un
{
	int i;
	char c;
};
int main() {

	union Un un;
	// 下面输出的结果是一样的吗?
	printf("%d\n", &(un.i));
	printf("%d\n", &(un.c));
	return 0;
}

程序运行结果为:
在这里插入图片描述
说明在内存中联合的存储就为不才画的内存图。

4.2、联合大小的计算

  • 联合的大小至少是最大成员的大小。
  • 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
  • 对齐数的计算方法与结构体相同
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));
	return 0;
}

结果为:
在这里插入图片描述
内存草图为:
在这里插入图片描述
此时,我们可以利用联合体的特性,来判断当前程序是大端存储还是小段存储。

union Un
{
	int i;
	char c;
};
int main() {
	union Un un1;
	un1.i = 0x1;
	printf("%c", un1.c);
	if (un1.c == 0x01) {
		printf("小端\n");
	}
	else {
		printf("大端\n");

	}
	return 0;
}

结果为:小端
在这里插入图片描述


以上就是本章所有内容。若有勘误请私信不才。万分感激💖💖 若有帮助不要吝啬点赞哟~~💖💖

ps:表情包来自网络,侵删🌹

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

初始JavaEE篇 —— 文件操作与IO

找往期文章包括但不限于本期文章中不懂的知识点: 个人主页:我要学编程程(ಥ_ಥ)-CSDN博客 所属专栏:JavaEE 目录 文件介绍 Java标准库中提供操作文件的类 文件系统操作 File类的介绍 File类的使用 文件内容操作 二进制文件的读写操作…

CSP 2024 入门级第二轮 CSP-J 2024 复赛 第一题 扑克牌

一、题目阅读 [CSP-J 2024] 扑克牌 - 洛谷 二、题目解析 输入 去重 三、题目代码 #include <bits/stdc.h> using namespace std;int main() {map<string, bool> flag;int n, res 52;cin >> n;while (n--) {string s;cin >> s;if (!flag[s]) { // …

面试题:JVM(二)

1. 面试题 简述 Java 类加载机制?&#xff08;百度&#xff09; JVM类加载机制 &#xff08;滴滴&#xff09; JVM中类加载机制&#xff0c;类加载过程&#xff0c;什么是双亲委派模型&#xff1f; &#xff08;腾讯&#xff09; JVM的类加载机制是什么&#xff1f; &#x…

AUTOSAR CP MCAL微控制器抽象层介绍

AUTOSAR(Automotive Open System Architecture)即汽车开放系统架构,它将汽车电子控制单元(ECU)的软件底层做了一个标准的封装,使得开发者能够共用一套底层软件,并通过修改参数来匹配不同的硬件和应用层软件。AUTOSAR CP(Classic Platform)是AUTOSAR架构中的一个重要组…

ElastricSearch 原理以及简单实用(超级通俗)

提到非结构化数据的检索&#xff0c;常常用到 ElasticSearch&#xff0c;他是什么呢&#xff1f; ElasticSearch 是一个基于 Apache Lucene 的分布式搜索引擎&#xff0c;可以作为实时文档存储系统&#xff0c;且文档的每一个内容都可以被检索&#xff0c;能够处理 PB 级别的结…

在线培训知识库:企业培训的新篇章

在当今快节奏的商业环境中&#xff0c;员工培训已成为企业保持竞争力的关键。在线培训知识库作为一种新兴的培训工具&#xff0c;正逐渐成为企业培训体系的核心。它不仅能够提供灵活的学习方式&#xff0c;还能确保培训内容的及时更新和高效传播。本文将探讨在线培训知识库的重…

简单的kafkaredis学习之kafka

简单的kafka&redis学习整理之kafka 1. kafka 1.1 什么是消息队列 在学习Kafka之前我们先来看一下什么是消息队列&#xff0c;消息队列(Message Queue)&#xff1a;可以简称为MQ 例如&#xff1a;Java中的Queue队列&#xff0c;也可以认为是一个消息队列 消息队列&#x…

【连续多届检索,ACM出版】第四届大数据、人工智能与风险管理国际学术会议 (ICBAR 2024,11月15-17)--冬季主会场

第四届大数据、人工智能与风险管理国际学术会议 (ICBAR 2024)--冬季主会场 2024 4th International Conference on Big Data, Artificial Intelligence and Risk Management 会议官网&#xff1a;www.icbar.net 2024 4th International Conference on Big Data, Artificial I…

集成框架 -- 自定义二方包 starter

自定义starter 二方包 My-thread-pool-startermy-thread-pool-starter 整体架构 测试 MyTestAppApplication测试工程 my-test-app 结构测试项目的 pom.xml 二方包 My-thread-pool-starter POM 文件 <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi&…

如何看待AI技术的应用前景?

文章目录 如何看待AI技术的应用前景引言AI技术的现状1. AI的定义与分类2. 当前AI技术的应用领域 AI技术的应用前景1. 经济效益2. 社会影响3. 技术进步 AI技术应用面临的挑战1. 数据隐私与安全2. 可解释性与信任3. 技能短缺与就业影响 AI技术的未来发展方向1. 人工智能的伦理与法…

华为擎云(银河麒麟V10+麒麟9000C CPU)电脑总是弹出“选择新密钥环的密码”(20241030)

症状如下图&#xff1a; 网络上一般的解决方法都是安装 seahorse &#xff0c;例如这篇文章:银河麒麟系统清除桌面密钥环 不知道为什么&#xff0c;这对我的这台电脑并不可行。 麒麟系统用的是 Gnome 桌面。这个“密钥环”的弹出框是由 gnome-keyring-daemon 弹出的。这是一个…

[SICTF Round4] PWN

这PWN题似乎是给我出的&#xff0c;4个一血1个2血。密码又过于简单。逆向太难了又不大会。 Stack fengshui main可以溢出覆盖rbpret所以它每一步都需要移栈。 可用的ROP里没有pop rdi,在4004c0里有错位的01 5d c3 &#xff1a;add DWORD PTR [rbp-0x3d], ebx 并且有对应的p…

yaml文件编写

Kubernetes 支持YAML和JSON格式管理资源 JSON 格式:主要用于 api 接口之间消息的传递 YAML 格式;用于配置和管理,YAML是一种简洁的非标记性语言,内容格式人性化容易读懂 一&#xff0c;yaml语法格式 1.1 基本语法规则 使用空格进行缩进&#xff08;不使用制表符&#xff0…

2025浙江省考报名流程详细教程

2025年浙江省考报名马上就要开始了&#xff0c;有想要参加浙江省考的同学&#xff0c;可以提前看一下报名流程&#xff0c;和报名照要求。 报名时间&#xff1a;11月6日9时一11月11日17时 南核时间&#xff1a;11月6日9时一11月13日17时 缴费时间&#xff1a;11月14日9时一11月…

江协科技STM32学习- P30 FlyMCU串口下载STLink Utility

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

HarmonyOS鸿蒙开发入门,常用ArkUI组件学习(一)

刚开始接触HarmonyOS的开发&#xff0c;希望不会太晚。在我学习的过程中&#xff0c;我会将我学到的内容&#xff0c;通过写博客的形式&#xff0c;来进行回忆和复习。同时也希望能够遇到志同道合的朋友&#xff0c;我们一起学习&#xff0c;一起进步&#xff0c;文章中有什么不…

shell脚本案例:创建用户和组

使用场景 在部署程序时&#xff0c;往往首要任务是创建用户和组。有的程序可能用到的组、用户比较多&#xff1b;且不知道服务器环境是否已经有了所需的组和用户。所以针对这个情况&#xff0c;根据Oracle RAC部署时的实际情况写了个脚本。 Linux版本 脚本代码 #!/bin/bash …

【设计模式】结构型模式(一):适配器模式、装饰器模式

结构型模式&#xff08;一&#xff09;&#xff1a;适配器模式、装饰器模式 1.适配器模式&#xff08;Adapter&#xff09;2.装饰器模式&#xff08;Decorator&#xff09;2.1 主要特点2.2 组成部分2.3 示例代码2.3.1 Component 组件2.3.2 ConcreteComponent 具体组件2.3.3 Dec…

交换机的基本配置

交换机的基本配置 实验题目实验目的实验任务实验设备实验环境实验步骤VLAN 的简单配置跨交换机 vlan 的配置主机配置信息表解释&#xff1a; vlan 间路由 实验题目 交换机的基本配置。 实验目的 1) 理解交换机的原理和应用场景&#xff1b; 2) 交换机的基本指令系统&#xf…

QFrameWork学习指南

QFramework官网地址&#xff1a;Wiki - 木兰确实 1、界面设计 &#xff08;1&#xff09;CounterAppController的界面 BtnAdd和BtnSub为Button组件&#xff0c;CountText为Text组件&#xff0c;后续的脚本挂载Canvas上。 &#xff08;2&#xff09;OnGUI OnGUI是Unity中通过…