C语言自定义类型之联合和枚举解读

 更新时间:2025年08月05日 14:09:24   作者:✿༺小陈在拼命༻✿  
联合体共享内存,大小由最大成员决定,遵循对齐规则;枚举类型列举可能值,提升可读性和类型安全性,两者在C语言中用于优化内存和程序效率

一、联合体

1.1 联合体类型的声明

像结构体⼀样,联合体也是由⼀个或者多个成员构成,这些成员可以是不同的类型。

声明方式如下图:

那联合体和结构体究竟有什么区别呢??

下面将重点讲解联合体的特点!!

1.2 联合体的特点

1.2.1 特点1

所有成员共⽤同⼀块内存空间。所以联合体也叫:共⽤体

我们可以发现,三个地址打印出来是一样的。那既然都共用一块空间,那大小有多大呢??

1.2.2 特点2

编译器只为最大的成员分配⾜够的内存空间(因为联合体至少得有能力保护最大的那个成员)

1.2.3 特点3

给联合体其中⼀个成员赋值,其他成员的值也跟着变化。

这里为什么打印出来的是11223355呢,我们根据3个特点,可以分析画出un的内部布局图

充分说明了特点3!

1.3 联合体的大小

特点2提到,编译器只为联合体最大的成员分配足够的空间,那联合体的大小就一定等于最大成员变量的大小吗??

答案是不对的,我们可以看看下面的代码

我们可以验证出,虽然编译器只为最大的成员分配足够空间,但不代表联合体的大小就是最大成员变量的大小!!!

联合体的大小要遵循以下两个特点:

1、联合的大小⾄少是最⼤成员的大小。

2、当最⼤成员大小不是最大对齐数的整数倍的时候,就要对⻬到最⼤对⻬数的整数倍。

这说明,联合体虽然可以节省空间,但也不是一味地节省,他也是有自己的对齐规则的。

分析上图代码:

  • Un1的第一个成员数组虽然是5个字节的大小,但是最大对齐数只能取char类型,所以是1,而int是4,所以Un1的最大对齐数是4,为了保证能放下5个字节的空间,所以最大对齐数翻倍变成8!
  • Un2的第一个成员数组虽然是14个字节的大小,但最大对齐数只能取short类型,所以是2,而int是4,所以Un2的最大对齐数是4,为了保证能放下14个字节的空间,所以最大对齐数翻4倍变成16!

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

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

这说明使用联合体是可以节省空间的!!!

1.5 使用联合体节省空间的例子

⽐如,我们要搞⼀个活动,要上线⼀个礼品兑换单,礼品兑换单中有三种商品:图书、杯⼦、衬衫。 每⼀种商品都有:库存量、价格、商品类型和商品类型相关的其他信息

其他信息:

图书:书名、作者、⻚数

杯⼦:设计

衬衫:设计、可选颜⾊、可选尺⼨

如果直接用结构体的话

但我们会发现,如果创建book变量,那设计、颜色、尺寸属性就会浪费掉。如果创建cup变量,那书名、作者、页数、可选颜色、尺寸属性就会浪费掉。如果创建shirt变量,那书名、作者、页数属性就会浪费掉。这样就会导致内存出现浪费,因为对于礼单兑换单的商品来说,只有部分属性是通用的,所以我们就可以将公共属性单独写出来,剩余属于各种商品自身属性使用联合体联合起来没这样就可以减少所需的内存空间,再一定程度上节省内存,使得程序更加高效运行。

因为我们每个变量只使用一次,所以可以直接使用匿名结构体。

1.6 运用联合体判断大小端

1.7 利用联合体打印存储的字节内容

既然可以判断大小端,那其实也可以直接把存储的情况打印出来!!这是一个很神奇的代码!

二、枚举类型

2.1 枚举类型的声明

枚举顾名思义就是⼀⼀列举。

把可能的取值⼀⼀列举。

⽐如我们现实⽣活中:

⼀周的星期⼀到星期⽇是有限的7天,可以⼀⼀列举

性别有:男、女、保密,也可以⼀⼀列举

⽉份有12个⽉,也可以⼀⼀列举

三原⾊,也是可以意义列举

{ }中是枚举类型的可能取值,也叫做枚举常量。

这些可能取值本身都是由值的,默认是从0开始依次递增1,当然我们在声明的时候也可以自己赋初值,但是定义完成之后,就不能在该类型的外部去修改了!!

2.2 枚举类型的优点

1、增加代码的可读性和可维护性

比如我们在实现游戏时常常会这样去写

此时如果不和菜单建立联系

我们并不能一下子就看出来case1和case0的含义,可读性较差,可如果在这边使用枚举类型,就可以增加代码的可读性,并且后期在维护的时候也方便。

2、 和#define定义的标识符⽐较枚举有类型检查,更加严谨。

#define定义的标识符是不过是一个符号,而枚举是一种类型,有类型检查写代码会更加严谨

3、 便于调试,预处理阶段会删除 #define 定义的符号

枚举类型在调试的时候会显示出成员名,但是#define就不会,标识符会直接替换成数字,后期如果需要调试找错误就不利于发现问题

4.、使⽤⽅便,⼀次可以定义多个常量

5.、枚举常量是遵循作⽤域规则的,枚举声明在函数内,只能在函数内使⽤

枚举有作用域的概念,在一个函数内部使用,出了函数就不能用了,但是#define定义的标识符没有作用域概念,他是一个全局都可以使用的常量。

2.3 枚举类型的使用

使用方法:使⽤枚举常量给枚举变量赋值

那是否可以拿整数给枚举变量赋值呢?

在C语⾔中是可以的,但是在C++是不⾏的,C++的类型检查⽐ 较严格。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • C++浅析构造函数的特性

    C++浅析构造函数的特性

    构造函数主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用;析构函数主要作用在于对象销毁前系统自动调用,执行一 些清理工作
    2022-07-07
  • C++实现LeetCode(173.二叉搜索树迭代器)

    C++实现LeetCode(173.二叉搜索树迭代器)

    这篇文章主要介绍了C++实现LeetCode(173.二叉搜索树迭代器),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • C语言编程内存分配通讯录静态实现示例代码教程

    C语言编程内存分配通讯录静态实现示例代码教程

    这篇文章主要为大家介绍了C语言编程实现静态的通讯录示例代码教程,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2021-10-10
  • C语言实现abs和fabs绝对值

    C语言实现abs和fabs绝对值

    这篇文章主要介绍了C语言实现abs和fabs绝对值,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • C语言利用EasyX实现绘制足球图案

    C语言利用EasyX实现绘制足球图案

    这篇文章主要为大家详细介绍了C语言如何利用EasyX绘图库实现绘制一个简单的足球图案,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下
    2022-11-11
  • C++实现LeetCode(148.链表排序)

    C++实现LeetCode(148.链表排序)

    这篇文章主要介绍了C++实现LeetCode(148.链表排序),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C语言 ffmpeg与sdl实现播放视频同时同步时钟详解

    C语言 ffmpeg与sdl实现播放视频同时同步时钟详解

    使用ffmpeg和sdl实现播放视频后,需要再实现时钟同步才能正常的播放视频,尤其是有音频的情况,我们通常需要将视频同步到音频来确保音画同步
    2022-09-09
  • VS2019中QT连接及使用的方法步骤

    VS2019中QT连接及使用的方法步骤

    这篇文章主要介绍了VS2019中QT连接及使用的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • C++的数据共享与保护你了解吗

    C++的数据共享与保护你了解吗

    这篇文章主要为大家详细介绍了C语言零基础入门的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • OpenCV实现图像膨胀

    OpenCV实现图像膨胀

    这篇文章主要为大家详细介绍了OpenCV实现图像膨胀,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06

最新评论