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++学习之如何进行内存资源管理

    与java、golang等自带垃圾回收机制的语言不同,C++并不会自动回收内存,这往往会导致内存泄漏和内存溢出等问题,所以掌握C++中的内存管理技巧和工具是非常重要的,本文就来和大家详细讲讲
    2023-05-05
  • vscode工程中c_cpp_properties.json文件作用详细说明

    vscode工程中c_cpp_properties.json文件作用详细说明

    c_cpp_properties.json是Visual Studio Code的一个配置文件,用于定义C/C++编译器的路径、默认包含路径和预处理器定义,这篇文章主要给大家介绍了关于vscode工程中c_cpp_properties.json文件作用详细说明的相关资料,需要的朋友可以参考下
    2024-08-08
  • C语言实现模拟USB对8bit数据的NRZI编码输出

    C语言实现模拟USB对8bit数据的NRZI编码输出

    今天小编就为大家分享一篇关于C语言实现模拟USB对8bit数据的NRZI编码输出,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • C语言 数据结构之数组模拟实现顺序表流程详解

    C语言 数据结构之数组模拟实现顺序表流程详解

    顺序表,全名顺序存储结构,是线性表的一种,线性表用于存储逻辑关系为“一对一”的数据,顺序表自然也不例外,不仅如此,顺序表对数据的物理存储结构也有要求,跟随下文来具体了解吧
    2021-11-11
  • C++归并算法实例

    C++归并算法实例

    这篇文章主要介绍了C++归并算法,实例分析了C++实现基于归并算法合并线性表的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-07-07
  • C语言编写基于TCP和UDP协议的Socket通信程序示例

    C语言编写基于TCP和UDP协议的Socket通信程序示例

    这篇文章主要介绍了C语言编写基于TCP和UDP协议的Socket通信程序示例,其中TCP的客户端与服务器端采用多线程实现,需要的朋友可以参考下
    2016-03-03
  • C++实现图的邻接矩阵存储和广度、深度优先遍历实例分析

    C++实现图的邻接矩阵存储和广度、深度优先遍历实例分析

    这篇文章主要介绍了C++实现图的邻接矩阵存储和广度、深度优先遍历,实例分析了C++实现图的遍历技巧,非常具有实用价值,需要的朋友可以参考下
    2015-04-04
  • C语言进阶输入输出重定向与fopen函数使用示例详解

    C语言进阶输入输出重定向与fopen函数使用示例详解

    这篇文章主要为大家介绍了C语言进阶输入输出重定向与fopen函数的示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2022-02-02
  • c++传输文件到不同计算机上的示例代码

    c++传输文件到不同计算机上的示例代码

    这篇文章主要为大家详细介绍了c++传输文件到不同计算机上的相关知识,文中的示例代码简洁易懂,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-03-03
  • C++中成员函数和友元函数的使用及区别详解

    C++中成员函数和友元函数的使用及区别详解

    大家好,本篇文章主要讲的是C++中成员函数和友元函数的使用及区别详解,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-01-01

最新评论