C语言之联合体和枚举

news2024/9/24 17:20:26

目录

前言

一、联合体类型的声明

二、联合体的特点

三、联合体的大小计算

四、联合体的适用场景举例:

五、枚举类型的声明

六、枚举类型的优点

总结



前言

        本文主要讲述C语言的两种结构类型:联合体和枚举。


❤️感谢支持,点赞关注不迷路❤️


一、联合体类型的声明

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

联合体声明与结构体类似,只不过是使用 union 关键字

示例:

#include <stdio.h>

//联合类型的声明
union Un
{
	char c;
	int i;
};

int main()
{
	//联合变量的定义
	union Un un = { 0 };
	
	//计算连个变量的⼤⼩
	printf("%zu\n", sizeof(un));

	return 0;
}

运行结果:

解释:联合体的成员是共用同⼀块内存空间的,这样⼀个联合体变量的大小,至少是最大成员的大小,因为联合体至少得有能力保存最大的那个成员。上面 int 最大,所以是4个字节。


二、联合体的特点

联合体最大的特点应该就是所有成员共用一块空间了。

示例1:

#include <stdio.h>
 
//联合类型的声明
union Un
{
	char c;
	int i;
};

int main()
{
	//联合变量的定义
	union Un un = { 0 };

	//下⾯输出的结果是⼀样的吗?
	printf("%p\n", &(un.i));
	printf("%p\n", &(un.c));
	printf("%p\n", &un);

	return 0;
}

运行结果:

解析:很明显两个成员变量地址和联合体变量名地址是一样的,代表着两个成员变量共用着一块空间

示例2:

#include <stdio.h>

//联合类型的声明
union Un
{
	char c;
	int i;
};

int main()
{
	//联合变量的定义
	union Un un = { 0 };
	un.i = 0x11223344;
	un.c = 0x55;
	printf("%x\n", un.i);

	return 0;
}

运行结果:

解析:通过调试我们可以看到两次赋值的变化,第二次赋值因为 c 是 char 类型,所以只有1个字节的访问权限,它只能修改第一个地址处的数据,也就是低地址44的位置,将其修改为55,VS是小端存储,打印出来是“反着打印”,所以是11223355 

相同成员的结构体和联合体对比:

我们再对比一下相同成员的结构体和联合体的内存布局情况。

#include <stdio.h>

struct S
{
	char c;
	int i;
};

union Un
{
	char c;
	int i;
};

int main()
{
	struct S s = { 0 };
	union Un un = { 0 };

	return 0;
}

画图分析:


三、联合体的大小计算

  • 联合的大小至少是最大成员的大小。
  • 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
  • 注意:数组一类的对齐数是以数组元素类型为准

示例:

#include <stdio.h>

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

union Un2
{
	short c[7];
	int i;
};

int main()
{
	//下⾯输出的结果是什么?
	printf("%zu\n", sizeof(union Un1));
	printf("%zu\n", sizeof(union Un2));

	return 0;
}

运行结果:

注意:数组以元素类型为自身对齐数,但是以总大小参与比较最大成员。

我们画图分析:


四、联合体的适用场景举例:

        使用联合体是可以节省空间的,举例: 比如,我们要搞一个活动,要上线一个礼品兑换单,礼品兑换单中有三种商品:图书、杯子、衬衫。 每⼀种商品都有:库存量、价格、商品类型和商品类型相关的其他信息。设计一种结构描述上述三种商品

  • 图书:书名、作者、页数
  • 杯子:设计
  • 衬衫:设计、可选颜色、可选尺寸

第一种:普通结构体方法

struct gift_list
{
	//公共属性
	int stock_number;//库存量
	double price; //定价
	int item_type;//商品类型

	//特殊属性
	char title[20];//书名
	char author[20];//作者
	int num_pages;//⻚数
	char design[30];//设计
	int colors;//颜⾊
	int sizes;//尺⼨
};

用上述结构实例出三种商品,除了公共属性,其他按照自身有的特殊属性赋值。我们可以发现每一种商品都会浪费一些不用的特殊属性占用的内存。

第二种:结构体嵌套联合体方法

struct gift_list
{
    //公共属性
    int stock_number;//库存量
    double price; //定价
    int item_type;//商品类型

    //特殊属性
    union {
        struct
        {
            char title[20];//书名
            char author[20];//作者
            int num_pages;//⻚数
        }book;

        struct
        {
            char design[30];//设计
        }mug;

        struct
        {
            char design[30];//设计
            int colors;//颜⾊
            int sizes;//尺⼨
        }shirt;

    }item;
};

在特殊属性里面每个商品单独使用一个特有的结构,由于联合体的特殊性——内存共用,也只能使用一个结构,这样能⼀定程度上节省内存。


五、枚举类型的声明

枚举顾名思义就是⼀⼀列举, 把可能的取值⼀⼀列举。

枚举声明使用 enum 关键字

示例:

#include <stdio.h>

enum Day//星期
{
	Mon,
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun  //中间使用逗号分隔,最后一个不用
};

int main()
{
	printf("%d\n", Mon);
	printf("%d\n", Tues);
	printf("%d\n", Wed);
	printf("%d\n", Thur);
	printf("%d\n", Fri);
	printf("%d\n", Sat);
	printf("%d\n", Sun);

	return 0;
}

运行结果:

解析:我们可以看到,枚举的成员都是有一个值的,默认是从0开始递增,并且枚举常量可以直接使用,不需要实例出变量使用,这一点与 #define 定义常量类似

1.枚举常量是可以在声明时修改值的,声明之外是不能修改的,这也是为什么叫枚举常量

#include <stdio.h>

enum Color//颜⾊
{
	RED = 2,
	GREEN = 4,
	BLUE = 8
};

int main()
{
	printf("%d\n", RED);
	printf("%d\n", GREEN);
	printf("%d\n", BLUE);

	return 0;
}

运行结果:

注意:如果是修改中间某一个值的话,在这个值之前的会默认从0开始递增,在这个值之后的会以这个值开始往后递增。

如:

#include <stdio.h>

enum Color//颜⾊
{
	RED,
	GREEN = 4,
	BLUE 
};

int main()
{
	printf("%d\n", RED);
	printf("%d\n", GREEN);
	printf("%d\n", BLUE);

	return 0;
}

运行结果:

2.枚举类型也是可以实例出变量的,只不过只能使用该枚举成员赋值。

#include <stdio.h>

enum Color//颜⾊
{
	RED,
	GREEN,
	BLUE
};

int main()
{
	enum Color a = RED;

	printf("%d\n", a);

	return 0;
}

注意:虽然在.c文件中上述 a 可以赋值任意整形,但是在.cpp中就不支持了,只能赋值枚举常量,因为c++的类型检查比较严格


六、枚举类型的优点

为什么使用枚举?

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

枚举的优点:

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

小结:枚举的作用需要自己在代码中体会,我感受到一点就是,在某些场景下,相比于给变量赋值一个数字,赋值一个枚举常量能大大增加代码的可读性,便于维护。


总结

        以上就是本文的全部内容,感谢支持。

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

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

相关文章

计算polydata相交

使用vtk.vtkBooleanOperationPolyDataFilter() 可以进行求交&#xff0c;差&#xff0c;并操作 并且可以填充交面&#xff0c;不会形成一个缺口 vtkBooleanOperationPolyDataFilter 计算由两个输入表面定义的体积计算出的并集、交集或差集的边界。 这两个表面不需要是流形的…

六,Spring Boot 容器中 Lombok 插件的详细使用,简化配置,提高开发效率

六&#xff0c;Spring Boot 容器中 Lombok 插件的详细使用&#xff0c;简化配置&#xff0c;提高开发效率 文章目录 六&#xff0c;Spring Boot 容器中 Lombok 插件的详细使用&#xff0c;简化配置&#xff0c;提高开发效率1. Lombok 介绍2. Lombok 常用注解2.1 ToString2.2 Se…

数字经济时代,零售企业如何实现以消费者为中心的数字化转型?

在数字经济时代&#xff0c;零售企业正面临着前所未有的挑战与机遇。随着消费者行为的数字化和多样化&#xff0c;传统的零售模式已难以满足市场需求。为了在激烈的市场竞争中立于不败之地&#xff0c;零售企业必须实现以消费者为中心的数字化转型。这一转型不仅仅是技术的升级…

[ios]准备好app后使用xcode发布ios操作

在app代码完成后&#xff0c;点击xcode进行发布

嵌入式开发学习路线(25届校招学习) 嵌入式学习路线七年规划:从大一小白到校招大佬 (学习路线汇总)

嵌入式开发学习路线&#xff08;25届校招可以参考&#xff09; 嵌入式系统作为当前最热门且最有发展前途的IT应用领域之一&#xff0c;吸引了大量有志于从事该行业的学习者。为了系统地掌握嵌入式开发技能&#xff0c;以下是一条详细的学习路线&#xff0c;旨在帮助初学者逐步…

算法:图片压缩算法【Z字行扫描】(Java实现)

要在Java中实现Z字形扫描&#xff0c;我们需要遍历一个给定的nn矩阵&#xff0c;并按照Z字形的顺序输出其元素。Z字形扫描的路径通常是从矩阵的左上角开始&#xff0c;沿着对角线方向交替向下和向上移动&#xff0c;直到遍历完整个矩阵。 下面是一个简单的Java实现示例&#xf…

不同vlan之间的通信方法

1.通过路由器的物理接口 1.给PC1,PC2配置IP地址&#xff0c;网关2.进入交换机配置vlan&#xff0c;交换机所有口都配置access口并绑定vlan3.配置路由器&#xff0c;进入路由器的两个接口配置网关IP和掩码缺点&#xff1a;成本高&#xff0c;每增加一个vlan就需要一个物理端口和…

【项目管理】项目管理办公室 --- PMO

项目管理办公室 PROJECT MANAGEMENT OFFICE 简称PMO 项目管理办公室Project Management Office&#xff0c;简称PMO 是现代企业管理中一个至关重要的组成部分&#xff0c;特别是在那些依赖项目驱动战略的企业中。 PMO的设立旨在提升项目管理的专业性和一致性&#xff0c;通过…

ctfshow-文件包含(web78-web88/web116-web117)

web78 <?phpif(isset($_GET[file])){$file $_GET[file];include($file); }else{highlight_file(__FILE__); } 判断是否存在file参数 如果存在 将包含这个参数值 文件 php://filter可以获取指定文件源码。当它与包含函数结合时&#xff0c;php://filter流会被当作php文件执…

智能生成ppt使用什么软件?免费生成软件大盘点

在快节奏的商务交流、生动有趣的课堂教育以及各类激情洋溢的演讲场合中&#xff0c;PPT&#xff08;PowerPoint Presentation&#xff09;无疑是我们不可或缺的信息传递利器。 然而&#xff0c;设计一份既视觉吸睛又能精准传达核心信息的PPT&#xff0c;往往需要耗费大量的时间…

Unity数据持久化 之 一个通过2进制读取Excel并存储的轮子(1)

本文仅作笔记学习和分享&#xff0c;不用做任何商业用途 本文包括但不限于unity官方手册&#xff0c;unity唐老狮等教程知识&#xff0c;如有不足还请斧正​​ 事先声明:该工具我是跟唐老师教程来的&#xff0c;并非原创&#xff0c;仅作学习笔记交流 1.需求分析 最终目的就如…

从供货上游到下游消费者平台搭建 多商家供货供应链商城开发关键点

搭建一个多商家供货的供应链商城、从供货上游到下游消费者的综合供应链平台是一个复杂的事情。但这样的平台能高效地连接供应链的各个环节&#xff0c;还能保证信息的流畅传递和业务的高效运作。今天&#xff0c;商淘云为您分享从供货上游到下游消费者的平台搭建的4大关键点&am…

MLLM(二)| 阿里开源视频理解大模型:Qwen2-VL

2024年8月29日&#xff0c;阿里发布了 Qwen2-VL&#xff01;Qwen2-VL 是基于 Qwen2 的最新视觉语言大模型。与 Qwen-VL 相比&#xff0c;Qwen2-VL 具有以下能力&#xff1a; SoTA对各种分辨率和比例的图像的理解&#xff1a;Qwen2-VL在视觉理解基准上达到了最先进的性能&#…

Qt中使用DAG(有向无环图)

之前做的一个视觉检测项目&#xff0c;本来各个视觉检测工具之间是独立的&#xff0c;单独执行图像输入、得出结果&#xff0c;然后综合汇总结果&#xff0c;简单明了。 后来要求工具之间能存在依赖关系&#xff0c;也就是A工具的输出可以作为B工具的输入&#xff0c;这样就很麻…

【Android】ViewPager基本用法总结

文章目录 一、添加ViewPager控件二、构建适配器类三、在 MainActivity 中设置适配器示例一&#xff1a;图片切换适配器MainActivity 示例二&#xff1a;Fragment切换适配器FragmentMainActivity ViewPager 是 Android 中一个用于在同一屏幕上滑动不同页面&#xff08;通常是左右…

【C++】C++中的花式操作:lambda表达式、类成员初始化列表、三元运算符、运算符及其重载。。。

八、C中的花式操作&#xff1a;lambda表达式、构造函数初始化列表、三元运算符 10、lambda表达式 见mutable关键字&#xff1a;【C】C中的关键字&#xff1a;const、mutable、auto、new....-CSDN博客。 11、构造函数初始化列表 当我们编写一个类时&#xff0c;一般都要有一个…

鼠标指针美化 一大批鼠标指针特效 喜欢的快点收藏~!

鼠标指针美化 一大批鼠标指针特效 喜欢的快点收藏~&#xff01;鼠标指针美化&#xff0c;这个功能可能许多人都没用过&#xff0c;应该还有很多人都是用着系统默认的鼠标指针&#xff0c;我们今天给大家分享一个可以修改鼠标指针的工具&#xff0c;如果你也喜欢&#xff0c;那麻…

类比推理-错题集

001 解析 &#xff1a; 002

[Visual Stuidio 2022使用技巧]3.模板

本文主要介绍本人在使用vs2022开发WPF桌面程序时使用到的一些插件及配置。 语言&#xff1a;C# IDE&#xff1a;Microsoft Visual Studio Community 2022 框架&#xff1a;WPF&#xff0c;.net 8.0 一、工程模板 1.1 创建模板 编辑好模板代码&#xff0c;扩展及NuGet包之…

【2024全国大学生数学建模竞赛】E题 模型建立与求解(含代码与论文)

目录 一、问题重述 1.1 问题背景 1.2 问题回顾与分析 四、问题求解与分析 4.1 问题1求解与分析 4.1.1 问题1分析 4.1.2 问题1建模与求解 按照提交论文的格式进行撰写&#xff01;完整版请看文章最后&#xff01; 一、问题重述 1.1 问题背景 随着城市化进程的加快、机动…