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

c语言进阶 自定义类型 枚举,联合

自定义类型 枚举 联合

    • 枚举
      • 1. 枚举类型的定义​
      • 2. 枚举的优点
      • 2. 枚举的优点
      • 3. 枚举的使用
      • 枚举的实际应用场景​
      • 枚举的实际应用场景
    • 联合
      • 1. 联合类型的声明、定义与大小计算
      • 2. 联合的特点
      • 3. 联合大小的计算规则
      • 联合的实际应用场景
      • 联合的实际应用场景
    • 枚举与联合的区别

枚举

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

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

1. 枚举类型的定义​

  • 枚举是一种用于定义命名常量集合的自定义类型,使用enum关键字声明。它将一组具有逻辑关联的离散值整合在一起,每个值都有一个有意义的名称。​
  • 示例:​
// 定义表示星期的枚举类型enum Day​
enum Day​
{​Mon,   // 第一个枚举常量,默认值为0​Tues,  // 第二个枚举常量,值为前一个常量值+1,即1​Wed,   // 值为2​Thur,  // 值为3​Fri,   // 值为4​Sat,   // 值为5​Sun    // 值为6​
};
  • 枚举常量的值规则:​
    • 若未显式赋值,第一个枚举常量默认值为 0,后续常量的值依次在前一个基础上加 1。​
    • 可以在定义时为枚举常量显式赋值,打破默认递增规则。显式赋值后,后续未赋值的常量仍按前一个常量值加 1 的规则取值。​

显式赋值示例:

enum Color
{RED = 1,    // 显式赋值为1GREEN,      // 前一个常量值为1,故该值为2BLUE = 4,   // 显式赋值为4YELLOW      // 前一个常量值为4,故该值为5
};

此时,RED的值为 1,GREEN的值为 2,BLUE的值为 4,YELLOW的值为 5。

2. 枚举的优点

2. 枚举的优点

  • #define定义常量相比,枚举具有以下显著优点:
  1. 增强代码可读性和可维护性
    • #define定义的常量是孤立的,如#define MON 0#define TUES 1,仅从常量名难以直观看出它们之间的关联。
    • 枚举将相关常量组合在一个类型中,如enum Day中的MonTues等,清晰地表明它们都属于星期这一类别,代码含义更明确。当需要修改常量值时,只需在枚举定义中修改,无需在代码中逐个查找#define的位置,维护更便捷。
  2. 具备类型检查,更严谨
    • #define定义的常量在预处理阶段会被直接替换为对应的值,没有类型概念。例如#define RED 1,在代码中int a = RED是合法的,char b = RED也合法,编译器不做类型检查。
    • 枚举常量属于特定的枚举类型,枚举变量只能接收该枚举类型的常量(虽然C语言允许隐式转换,但编译器可能会给出警告)。例如:
enum Color { RED, GREEN, BLUE };
enum Color clr;
clr = RED;    // 合法,类型匹配
clr = 1;      // 不推荐,编译器可能警告(int类型赋值给enum Color类型)

3. 避免命名污染:

  • #define定义的常量作用域是全局的,若在不同地方定义同名常量,会导致命名冲突。例如:
#define MAX 100
// 在另一个地方
#define MAX 200  // 编译错误,重复定义
  • 枚举常量的作用域局限于枚举类型内部,不同枚举类型中可以有同名常量,不会冲突。例如:​
enum A { MAX = 100 };enum B { MAX = 200 };  // 合法,两个MAX属于不同枚举类型​
  1. 便于调试:​
    调试时,枚举常量会以其名称显示,而#define定义的常量会显示为替换后的数值。例如调试包含enum Day { Mon, Tues }的代码时,变量值为Mon会显示Mon,而#define MON 0会显示0,使用枚举更易追踪变量含义。​
  2. 一次定义多个相关常量,使用便捷:​
    定义一组相关常量时,#define需要逐个定义,如:​
#define RED 1
#define GREEN 2
#define BLUE 3


枚举只需在{}中列出所有常量,一次定义完成,语法更简洁:​

enum Color { RED = 1, GREEN = 2, BLUE = 3 };​
​

3. 枚举的使用

  • 枚举类型定义后,需定义枚举变量来使用,且应使用枚举常量为枚举变量赋值,以保证类型的一致性和代码的规范性。
  • 示例
enum Color
{RED = 1,GREEN = 2,BLUE = 4
};
// 定义枚举变量clr,并使用枚举常量GREEN赋值
enum Color clr = GREEN;

注意事项:​

  • 虽然 C 语言允许将整数直接赋值给枚举变量(如clr = 5),因为枚举在底层是按整数存储的,但这种做法破坏了枚举的类型特性,可能导致代码逻辑混乱。例如5并非enum Color中定义的常量,将其赋值给clr后,后续判断clr的值时可能出现非预期结果。​
  • 规范的用法是仅使用枚举类型中定义的常量为枚举变量赋值,确保枚举变量的值始终在预期的范围内。

枚举的实际应用场景​

枚举的实际应用场景

  • 枚举在实际开发中常用于表示固定的状态、选项等。
  1. 表示状态
    • 示例:在游戏开发中,用枚举表示游戏角色的状态。
enum PlayerState
{IDLE,    //  idle状态,角色静止RUNNING, //  running状态,角色奔跑JUMPING, //  jumping状态,角色跳跃ATTACKING//  attacking状态,角色攻击
};
// 定义角色状态变量
enum PlayerState state = IDLE;
// 根据状态执行不同操作
if (state == RUNNING)
{// 执行奔跑相关逻辑
}

这样的代码清晰明了,看到state == RUNNING就知道是角色处于奔跑状态。​

  1. 表示选项:​
    • 示例:在配置相关的代码中,用枚举表示不同的配置选项。
 enum ConfigOption
{LOW,   //  低配置MEDIUM,//  中配置HIGH   //  高配置
};
// 选择配置
enum ConfigOption option = MEDIUM;

相较于用012表示配置,枚举让代码的意图更明确。

联合

1. 联合类型的声明、定义与大小计算

  • 联合(共用体)是一种特殊的自定义类型,其所有成员共享同一块内存空间。
  • 联合类型的声明:
// 声明联合类型union Un,包含char和int两种类型的成员
union Un
{char c;  // char类型成员,占1字节int i;   // int类型成员,通常占4字节(不同系统可能有差异)
};
  • 联合变量的定义:​
// 定义union Un类型的变量un​
union Un un;
  • 联合大小的计算:​
    • 联合的大小至少是其最大成员的大小,因为要能容纳最大的成员。​
    • 对于union Unchar c占 1 字节,int i占 4 字节,最大成员大小为 4 字节,所以sizeof(un)的结果为4。​
    • 示例代码及输出:​
printf("%d\n", sizeof(un));  // 输出结果为4​

2. 联合的特点

  • 联合最核心的特点是所有成员共享同一块内存空间,这意味着:
    • 联合变量的地址和其各成员的地址相同。
    • 修改一个成员的值,会覆盖其他成员在该内存空间中的值,即修改一个成员会影响其他成员。
  • 示例:
union Un
{int i;   // 占4字节char c;  // 占1字节,与i共享内存
}u;// 给成员i赋值0x11223344(假设系统为小端存储,低地址存放低字节)
u.i = 0x11223344;
// 此时内存中存储的字节从低到高为:0x44、0x33、0x22、0x11// 给成员c赋值0x00,c占用的是内存的低地址部分
u.c = 0x00;
// 此时内存中低地址的字节被修改为0x00,内存存储变为:0x00、0x33、0x22、0x11
// 成员i的值也随之变为0x11223300

在这里插入图片描述

结论:由于联合成员共享内存,同一时刻只能有效使用一个成员,修改一个成员会改变其他成员的值,这是联合与结构体的本质区别(结构体成员各自占用独立的内存空间)。

3. 联合大小的计算规则

  • 联合大小的计算需遵循以下规则:
    1. 联合的大小至少是其最大成员的大小,以保证能容纳最大的成员。
    2. 当最大成员的大小不是联合中最大对齐数的整数倍时,联合的大小需要向上调整为最大对齐数的整数倍。
    3. 对齐数:对于联合中的每个成员,其对齐数为该成员类型的对齐数(通常默认对齐数为类型自身的大小,如char对齐数为1,short为2,int为4等,不同编译器可能有细微差异),联合的最大对齐数为所有成员对齐数中的最大值。
  • 示例1:计算union Un1的大小
union Un1
{char c[5];  // char类型对齐数为1,数组占5字节int i;      // int类型对齐数为4,占4字节
};
  • 最大成员大小为 5 字节(char c [5])。​
  • 联合的最大对齐数为 4int 类型的对齐数)。​
  • 5 不是 4 的整数倍,向上调整为 8(4 的 2 倍),所以sizeof(union Un1) = 8。​
    输出示例:
printf("%d\n", sizeof(union Un1));  // 输出8

示例 2:计算 union Un2 的大小​

union Un2
{short c[7];  // short类型对齐数为2,数组占14字节(2*7)int i;       // int类型对齐数为4,占4字节
};

最大成员大小为 14 字节(short c [7])。​
联合的最大对齐数为 4(int 类型的对齐数)。​
14 不是 4 的整数倍,向上调整为 16(4 的 4 倍),所以sizeof(union Un2) = 16。​
输出示例:​

printf("%d\n", sizeof(union Un2));  // 输出16​

联合的实际应用场景

联合的实际应用场景

  • 联合由于成员共享内存的特性,在一些特定场景下非常有用。
  1. 节省内存
    • 当需要存储不同类型的数据,但这些数据不会同时使用时,用联合可以节省内存。
    • 示例:一个数据结构,有时需要存储整数,有时需要存储字符,用联合比结构体更节省空间。
// 用联合
union Data
{int num;char ch;
};
// 用结构体
struct DataStruct
{int num;char ch;
};
// 比较大小
printf("联合大小:%d\n", sizeof(union Data));           // 输出4
printf("结构体大小:%d\n", sizeof(struct DataStruct));  // 输出8(假设int占4字节,char占1字节,考虑对齐)

​可以看到,联合比结构体更节省内存。​

  1. 判断系统大小端:​
    • 大小端是指数据在内存中的存储顺序,大端是高字节存低地址,小端是低字节存低地址。​
    • 示例:用联合判断系统是大端还是小端。​
union EndianCheck​
{int i;char c;};union EndianCheck ec;​
ec.i = 1;// 如果是小端,1的低字节存低地址,c的值为1;如果是大端,c的值为0​
if (ec.c == 1){printf("小端系统\n");}else{printf("大端系统\n");}​
​
  • 利用联合成员共享内存的特点,通过c的值可以判断系统的大小端。

枚举与联合的区别

  • 枚举和联合都是C语言中的自定义类型,但它们有明显的区别:
特点枚举联合
内存管理成员是独立的常量,不共享内存成员共享同一块内存
用途表示固定的离散值集合节省内存、处理不同类型数据但不同时使用的场景
大小计算枚举类型变量大小通常与int相同至少是最大成员的大小,且是最大对齐数的整数倍
成员关系成员是不同的常量,相互独立成员共享内存,修改一个影响其他
http://www.dtcms.com/a/291408.html

相关文章:

  • 【LeetCode 热题 100】208. 实现 Trie (前缀树)
  • Linux下SPI设备驱动开发
  • 1.Java中的异常有哪些?异常处理机制呢?
  • C# 异常处理
  • 统计与大数据分析专业转型金融行业指南
  • makefile-- 其他函数
  • Linux PCI总线子系统
  • 网络基础DAY15-RSTP
  • OpenGL鼠标控制沿着指定轴旋转
  • linux --frp内网穿透
  • 低速信号设计之 RMII
  • 服务器系统时间不准确怎么办?
  • C++ 中的默认构造函数:非必要,不提供
  • 缓存数组,并遍历循环读取数组
  • springboot实战篇1
  • Windows VS2019 编译 Apache Thrift 0.15.0
  • DigitalOcean 云平台上线 AMD MI325X GPU Droplet 服务器
  • 如何编写假设和约束---SRS软件需求规格指南系列
  • accelerate 在Pycham中执行的设置方法
  • C语言字符串相关函数
  • 【网络编程】网络传输-protobuf
  • Prometheus+altermanager搭配钉钉报警
  • 【PTA数据结构 | C语言版】旅游规划
  • qwen 提示词
  • 试用SAP BTP 02B:试用SAP HANA Cloud
  • Spring处理器和Bean的生命周期
  • Jenkins 不同节点间文件传递:跨 Job 与 同 Job 的实现方法
  • 西门子 WinCC预定义报警控件过滤条件
  • 尚庭公寓的结构
  • claude code提示词设计