C语言自定义类型联合和枚举(25)

news2024/10/6 0:24:41

文章目录

  • 前言
  • 一、联合体
    • 联合体的声明
    • 联合体的特点
    • 联合体和结构体内存布局对比
    • 联合体的大小计算
    • 联合体的实际使用样例
      • 礼品兑换单
      • 判断当前机器是大端还是小端
  • 二、枚举
    • 枚举的定义
    • 枚举类型的声明
    • 枚举类型的优点
    • 枚举类型的使用
  • 总结


前言

  关于自定义类型除了我们常用的结构体,其实还有联合与枚举也是属于自定义类型
  我们也来学习一下吧!


一、联合体

联合体的声明

联合体是一个或多个成员组成,其中成员可以是不同类型,并且所有成员共用同一块内存空间,所以联合体也称为共用体。联合体声明的关键字是union

//联合体类型的声明
union Un
{
	// 1 + 4 == 5 吗?
    char c; // 1
    int i; // 4
};
int main()
{
    union Un un;// 联合体的定义
    sizeof("%zd\n,sizeof(un)"); // 4
    
    return 0;
}

联合体的特点

  1. 联合体所有成员共用同一块内存空间,一个联合体变量的大小,至少是最大成员的大小,编译器只为最大的成员分配足够大的空间
  2. 给联合体其中一个成员赋值,其他成员的值也会变化

我们不妨来两段代码来详细感受一下这个性质:

// 代码一
union Un
{
    char c;
    int i;
};

int main()
{
    union Un un = {0};
    // 下⾯输出的结果是⼀样的吗?
    // 结果:001AF85C
    //      001AF85C
    //	    001AF85C
    printf("%p\n", &(un.i));
    printf("%p\n", &(un.c));
    printf("%p\n", &un);
    
    return 0;
}
// 代码二
union Un
{
    char c;
    int i;
};

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

    un.i = 0x11223344;
    un.c = 0x55;
    
	// 结果:11223355
    printf("%x\n", un.i);
    
    return 0;
}

如果用一幅图来说明,那就是如下:
在这里插入图片描述
从代码一输出的结果是相同的,说明联合体中成员变量是一块空间存储
从代码二输出中,第四个字节的内容被修改位55,对联合体中成员赋值,会影响联合体的全部成员,char类型只占用一个字节

还记得前面的内容不,请在十秒内说出这是小端存储还是大端存储?
答案是小端!

联合体和结构体内存布局对比

我们再来比较一下同样成员变量情况下,两种结合方式的区别来加深印象:

struct Su
{
    char c;
    int i;
}S;

Union Un
{
    char c;
    int i;
}un;

在这里插入图片描述

结构体是通过以为空间换取时间设计,而联合体是节省空间

联合体的大小计算

  1. 联合体的大小至少是最大成员的大小
  2. 当最大成员大小(联合体总大小)要对齐到最大对齐数的整数倍

请注意,很多学习资料都说联合体的大小就是最大成员的大小,其实这是不对的!
事实上,联合体也是有内存对齐的,下面我们就来举例说明

#include <stdio.h>

union Un1
{
    char c[5]; 
        int i; 
}; // 最大对齐数位4,最大成员大小为5,对齐到8是最大对齐数的整数倍

union Un2
{
    short c[7];
    int i;
}; // 最大对齐数位4,最大成员大小为7,对齐到16是最大对齐数的整数倍

int main()
{
    printf("%zd\n", sizeof(union Un1)); // 8
    printf("%zd\n", sizeof(union Un2)); // 16
    return 0;
}

联合体的实际使用样例

礼品兑换单

事实上你可以观察下这种做法,把公共属性单独写出来,剩余属于各种商品本身的属性使用联合体处理,其实是在一定程度上节省了内存

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;
};

判断当前机器是大端还是小端

这算是一个巧思,很妙,因为联合体公用一个空间,相当于我是把一个int变量的第一个字节的数据单独提取出来,如果最后返回的是1,那说明低字节位放数据低位,事实也确实是这样,也就说明小端是答案

union un
{
	char c;
	int i;
};

bool check_sys()
{
	union un u;
	u.i = 0x00000001;

	return u.c;
}

int main()
{
	if (check_sys()){
		printf("小端\n"); // YES
	}
	else printf("大端\n");

	return 0;
}

二、枚举

枚举的定义

枚举顾名思义就是一一列举,而列举可能的取值是用于定义一组具有离散值的常量,使数据更简洁、方便使用,关枚举的关键字enum

枚举类型的声明

enum Day
{
    Mon,
    Tues,
    Wed,
    Thur,
    Fri,
    Sat,
    Sun
};

enum Sex
{
    Man,
    Woman;
}

以上定义的enum Day、enum Sex都是枚举类型,而{ }中枚举类型的可能取值称为枚举常量

枚举类型的优点

我么可以用宏来定义常量,那么这里为什么还要单独设立一种数据类型呢?

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

枚举类型的使用

enum Color
{
	Red=2,
    Blue=1
}

enum Color clr = Blue;

enum Color clr = 2;
这种写法可以么,毕竟2也是Red的值,应该支持隐式类型转换吧!
嗯…最好不要,C语言可以;Cpp不行,Cpp检查比较严格

那有没有具体一点的应用场景呢?
有,我们稍微回顾一下之前的扫雷
在这里插入图片描述
运用了枚举这个技巧后:

在这里插入图片描述

关于枚举其实我们后来还会有很多的应用场景,这就需要大家自己去慢慢发现了!


总结

  其实中途跳过去写Cpp了,现在再跳回来…
  反复横跳!

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

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

相关文章

Kubernetes-Operator篇-04-operator部署验证

1、部署命令 这个是很多博客教程都在使用的部署命令&#xff1a; make manifests make install export ENABLE_WEBHOOKSfalse make run我们使用之前的demo来进行部署验证&#xff1a;Kubernetes-Operator篇-02-脚手架熟悉 这里面涉及到的makefile的配置可以参考&#xff1a;…

10.5二分专练,二分边界情况,+1不加1的判断,方向判断,各种DEBUG

5 https://leetcode.cn/problems/minimum-speed-to-arrive-on-time/submissions/570242512/ 就是说总时间是 前n-1量汽车的运行时间&#xff0c;向上取整&#xff0c;然后再加上最后一辆列车的运行时间 最快的话是需要n-1个小时 搜索空间就是时速&#xff0c;左边界是1&#x…

数学建模 第三讲 - 简单的优化模型

在数学建模的学习过程中&#xff0c;第三章介绍了几种简单的优化模型&#xff0c;这些模型在实际生活中有广泛的应用。以下是对这些模型的整理和总结。 3.1 存贮模型 问题描述 配件厂为装配线生产产品&#xff0c;更换设备需要支付生产准备费&#xff0c;产量大于需求时需要…

Llama 3.2 微调指南

让我们通过微调 Llama 3.2 来找到一些精神上的平静。 我们需要安装 unsloth&#xff0c;以更小的尺寸实现 2 倍的快速训练 !pip install unsloth!pip uninstall unsloth -y && pip install --upgrade --no-cache-dir "unsloth[colab-new] githttps://github.co…

OpenCV马赛克

#马赛克 import cv2 import numpy as np import matplotlib.pyplot as pltimg cv2.imread(coins.jpg,1) imgInfo img.shape height imgInfo[0] width imgInfo[1]for m in range(200,400): #m,n表示打马赛克区域for n in range(200,400):# pixel ->10*10if m%10 0 and …

初识Linux · 文件(1)

目录 前言&#xff1a; 回顾语言层面的文件 理解文件的预备知识 文件和磁盘 使用和认识系统调用函数 前言&#xff1a; 本文以及下篇文章&#xff0c;揭露的都是Linux中文件的奥秘&#xff0c;对于文件来说&#xff0c;初学Linux第一节课接触的就是文件&#xff0c;对于C…

Windows删除service服务

Windows删除service服务 找到命令提示符&#xff1a; 右键&#xff0c;以管理员身份运行 输入&#xff1a; sc delete 服务名 Windows根据TCP端口号查找进程PID再kill进程_windows tcpkill-CSDN博客文章浏览阅读5.3k次&#xff0c;点赞42次&#xff0c;收藏104次。Windows根据…

【408计算机考研课程】数据结构-数据结构在学什么?

前言 数据结构在学什么&#xff1f; 如何用程序代码把现实世界的问题信息化如何用计算机高效地处理这些信息从而创造价值 第一章&#xff1a;数据结构在学什么&#xff1f; 总览 什么是数据&#xff1f; 简介&#xff1a;数据是信息的载体&#xff0c;是描述客观事物属性的数、…

【在Linux世界中追寻伟大的One Piece】进程信号

目录 1 -> 信号入门 1.1 -> 生活角度的信号 1.2 -> 技术应用角度的信号 1.3 -> 注意 2 -> 信号的概念 2.1 -> 用kill -l命令可以查看系统定义的信号列表 2.2 -> 信号处理常见方式 3 -> 产生信号 3.1 -> Core Dump 3.2 -> 调用系统函数…

已解决-Nacos明明成功运行,但Spring报错连接不上

这天使用windows本地nacos的时候&#xff0c;一直报错&#xff1a; Caused by: com.alibaba.nacos.api.exception.NacosException: Request nacos server failed: Caused by: com.alibaba.nacos.api.exception.NacosException: Client not connected, current status:STARTIN…

(计算机组成原理)

计算机的发展 计算机系统硬件&#xff08;计算机的实体&#xff0c;如主机&#xff0c;外设等&#xff09;软件&#xff08;由具有各种特殊功能的程序组成&#xff09; 硬件是计算机系统的物理基础&#xff0c;硬件决定瓶颈&#xff0c;软件决定性能发挥的程度 第一台电子数字计…

YOLOv4和Darknet实现坑洼检测

关于深度实战社区 我们是一个深度学习领域的独立工作室。团队成员有&#xff1a;中科大硕士、纽约大学硕士、浙江大学硕士、华东理工博士等&#xff0c;曾在腾讯、百度、德勤等担任算法工程师/产品经理。全网20多万粉丝&#xff0c;拥有2篇国家级人工智能发明专利。 社区特色…

IDEA如何自定义创建类的文档注释

说明&#xff1a;在IDEA中&#xff0c;创建一个Java类文件&#xff0c;会在类上面自动生成文档注释&#xff0c;如下&#xff1a; 看样子&#xff0c;默认是计算机的用户名&#xff0c;然后加上当前的创建时间。可以在IDEA中的Setting中设置&#xff0c;如下&#xff1a; /*** …

汽车追尾为什么是后车的责任?

简单点说&#xff1a;因为人后面没有长眼睛。 结论 在汽车追尾事故中&#xff0c;通常情况下后车被认为是责任方的原因在于交通法规对驾驶安全标准的约定和实践中的责任识别原则。虽然追尾事故常见地被归责于后车&#xff0c;但具体判断并不是绝对的&#xff0c;仍需综合多种…

C++11中的特性

这里主要讲解一些C11相较于C98所新增的比较实用的新特性。 C11的官方文档&#xff1a;C11 - cppreference.comhttps://en.cppreference.com/w/cpp/11 一、列表初始化&#xff08;List-initialization&#xff09; &#xff08;一&#xff09;、使用“{}”进行初始化 在C98中&…

有关自连接表的统一封装

表结构 RecursionBean Getter Setter ToString JsonInclude(JsonInclude.Include.NON_EMPTY) public class RecursionBean<T> extends BaseVO {/*** 编号*/private T id;/*** 父权限ID&#xff0c;根节点的父权限为空* 注释掉JsonIgnore&#xff0c;是为了前端判断是否…

Linux驱动开发常用调试方法汇总

引言&#xff1a;在 Linux 驱动开发中&#xff0c;调试是一个至关重要的环节。开发者需要了解多种调试方法&#xff0c;以便能够快速定位和解决问题。 1.利用printk 描述&#xff1a; printk 是 Linux 内核中的一个调试输出函数&#xff0c;类似于用户空间中的 printf。它用于…

CE找CSGO人物坐标和视角基址-幽络源原创

前言 幽络源站长本次免费分享的是CE找CSGO人物坐标和视角基址 本教程分为两篇&#xff0c;当前为上篇->找基址 所具备的知识 CE的使用 教程目的 通过CE找到一些基地址&#xff0c;然后结合Python实现CSGO的透视绘制&#xff0c;这里我们是纯手写透视。 第一步&#x…

如何使用CMD命令启动应用程序(二)

说明&#xff1a;去年1024发布了一篇博客&#xff0c;介绍如何使用CMD命令启动应用程序&#xff0c;但实际情况&#xff0c;有些程序可能无法用配置环境变量的方式来启动&#xff0c;本文针对两种情况下的程序&#xff0c;如何使用CMD命令来启动&#xff0c;算是对上一篇博客的…

Java开发必知必会的一些工具

本文主要介绍 Java 程序员应该学习的一些基本和高级工具。 如果你想成为一名更好的程序员&#xff0c;最重要的技巧之一就是学习你的编程工具。 Java 世界中存在着如此多的工具&#xff0c;从 Eclipse、NetBeans 和 IntelliJ IDEA 等著名的 IDE 到 JConsole、VisualVM、Eclipse…