C语言——联合和枚举

目录

一、联合体

1.1 联合体类型的声明

1.2 联合体的特点

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

1.4 联合体大小的计算 

1.5 联合的⼀个练习 

二、枚举类型 

2.1 枚举类型的声明

2.2 枚举类型的优点 

2.3 枚举类型的使用


一、联合体

1.1 联合体类型的声明

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

但是编译器只为最⼤的成员分配足够的内存空间。联合体的特点是所有成员共⽤同⼀块内存空间。所以联合体也叫:共用体

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

创建联合和创建结构的方式相同,需要一个联合模板和联合变量。下面是几种定义联合体变量的方法:

方法一:先创建模板,再定义变量

// 创建联合体模板union perdata
union perdata
{int Class;char Office;
};
// 使用该联合体模板创建两个变量a, b
union perdata a,b;

此处,perdata是联合体名,该名字是由我们任意定的,但是尽量起个有意义的名称。其相当于一个模板,可以使用这个模板去定义变量a、b。定义的时候不要忘了union

方法二:同时创建模板和变量

// 创建联合体模板union perdata的同时定义两个变量a、b
union perdata
{int Class;char Office;
}a,b;

这与方法一差不多。

方法三:省略联合体名

union
{int Class;char Office;
}a,b;

相对于方法一与方法二,此处省略了联合体名。虽然更简洁了,但是因为没有了名字,后面就不能用该联合体定义新的变量。

方法四:使用typedef

// 联合体模板union perdata重新命名为perdata_U
typedef union perdata
{int Class;char Office;
}perdata_U;
// 使用新名字perdata_U创建两个变量a, b
perdata_U a,b;

此处使用typedef为联合体模板union perdata定义一个别名perdata_U

初始化联合体

联合体的初始化与结构体不同,联合体只能存储一个值。联合体有三种初始化方法:

perdata_U a;
a.Class = 10;
perdata_U b = a;				/* 1、把一个联合初始化为另一个同类型的联合; */
perdata_U c = {20};				/* 2、初始化联合的第一个成员; */
perdata_U d = {.Office = 30};   /* 3、根据C99标准,使用指定初始化器。 */
1.2 联合体的特点

联合的成员是共用同⼀块内存空间的,这样⼀个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。

//代码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;
}

输出的结果:

代码1输出的三个地址⼀模⼀样,代码2的输出,我们发现将i的第4个字节的内容修改为55了。 我们仔细分析就可以画出,un的内存布局图。

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

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

struct S
{char c;int i;
};
struct S s = {0};union Un
{char c;int i;
};
union Un un = {0};

1.4 联合体大小的计算 

• 联合的大小至少是最大成员的大小。

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

#include <stdio.h>
union Un1
{char c[5];int i;
};
union Un2
{short c[7];int i;
};
int main()
{//下⾯输出的结果是什么?printf("%d\n", sizeof(union Un1));printf("%d\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;//尺⼨
};

上述的结构其实设计的很简单,⽤起来也方便,但是结构的设计中包含了所有礼品的各种属性,这样使得结构体的大小就会偏大,比较浪费内存。因为对于礼品兑换单中的商品来说,只有部分属性信息是常⽤的。比如:

商品是图书,就不需要design、colors、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;
};
1.5 联合的⼀个练习 

写⼀个程序,判断当前机器是大端?还是小端?

int check_sys()
{union{int i;char c;}un;un.i = 1;return un.c;//返回1是⼩端,返回0是⼤端
}

二、枚举类型 

2.1 枚举类型的声明

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

把可能的取值⼀⼀列举。

比如我们现实生活中:

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

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

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

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

这些数据的表示就可以使用枚举了。

enum Day//星期
{Mon,Tues,Wed,Thur,Fri,Sat,Sun
};
enum Sex//性别
{MALE,FEMALE,SECRET
};
enum Color//颜⾊
{RED,GREEN,BLUE
};

以上定义的 enum Day , enum Sex , enum Color 都是枚举类型。

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

这些可能取值都是有值的,默认从0开始,依次递增1,当然在声明枚举类型的时候也可以赋初值。 

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

枚举类型需要先定义后使用,这里的定义是类型的定义,不是枚举变量的定义。

既然枚举也是一种数据类型,那么它和基本数据类型一样也可以对变量进行声明。

方法一:枚举类型的定义和变量的声明分开

//先定义类型
enum DAY    //类型名称就是enum DAY
{MON=1, TUE, WED, THU, FRI, SAT, SUN
};//后声明变量
enum DAY yesterday;
enum DAY today;
enum DAY tomorrow; //变量tomorrow的类型为枚举型enum DAY
enum DAY good_day, bad_day; //变量good_day和bad_day的类型均为枚举型enum DAY

方法二:类型定义与变量声明同时进行

enum //跟第一个定义不同的是,此处的标号DAY省略,这是允许的。
{saturday,sunday = 0,monday,tuesday,wednesday,thursday,friday
} workday; //变量workday的类型为枚举型enum DAY//变量days的类型为枚举型enum week
enum week { Mon=1, Tue, Wed, Thu, Fri Sat, Sun} days; //定义枚举类型并声明了两个枚举型变量
enum BOOLEAN { false, true } end_flag, match_flag; 

第二种方式的变量定义是一次性的,后面要想再定义同类型变量就不行了。

第一种方式更灵活。

方法三:用typedef关键字将枚举类型定义成别名,并利用该别名进行变量声明

typedef enum workday
{saturday,sunday = 0,monday,tuesday,wednesday,thursday,friday
} workday; //此处的workday为枚举型enum workday的别名//或者
//enum workday中的workday可以省略
typedef enum
{saturday,sunday = 0,monday,tuesday,wednesday,thursday,friday
} workday; //此处的workday为枚举型enum workday的别名//定义变量
//变量today和tomorrow的类型为枚举型workday,也即enum workday
workday today, tomorrow; 

注意:

同一个程序中不能定义同名的枚举类型,不同的枚举类型中也不能存在同名的命名常量。

2.2 枚举类型的优点 

为什么使用枚举?

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

枚举的优点:

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

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

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

4. 使用方便,⼀次可以定义多个常量

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

2.3 枚举类型的使用

1、先声明后赋值(常用)

#include<stdio.h>/* 定义枚举类型 */
enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN };void main()
{/* 使用基本数据类型声明变量,然后对变量赋值 */int x, y, z;x = 10;y = 20;z = 30;/* 使用枚举类型声明变量,再对枚举型变量赋值 */enum DAY yesterday, today, tomorrow;yesterday = MON;today     = TUE;tomorrow  = WED;printf("%d %d %d \n", yesterday, today, tomorrow);
}

就像各种类型都有取值范围一样,枚举变量只能接收枚举类型中定义好的符号值(实质是一个int类型的数据)。

2、声明的同时赋值

#include <stdio.h>/* 定义枚举类型 */
enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN };void main()
{/* 使用基本数据类型声明变量同时对变量赋初值 */int x=10, y=20, z=30;/* 使用枚举类型声明变量同时对枚举型变量赋初值 */enum DAY yesterday = MON, today = TUE,tomorrow = WED;printf("%d %d %d \n", yesterday, today, tomorrow);
}

3、类型定义、变量声明和赋值同时进行(不推荐,会引入全局变量)

#include <stdio.h>/* 定义枚举类型,同时声明该类型的三个变量,并赋初值。它们都为全局变量 */
enum DAY
{MON=1, TUE,WED,THU,FRI,SAT,SUN 
}
yesterday = MON, today = TUE, tomorrow = WED;/* 定义三个具有基本数据类型的变量,并赋初值。它们都为全局变量 */
int x = 10, y = 20, z = 30;void main()
{printf("%d %d %d \n", x, y, z); //输出:10 20 30printf("%d %d %d \n", yesterday, today, tomorrow); //输出:1 2 3
}

 补充

对枚举型的变量可以直接赋任意整数值,如果赋值浮点数,也会自动去掉小数部分。

赋整数值时,可直接赋值,因为枚举的本质就是整型(int)数据的集合。

#include <stdio.h>int main()
{	enum week{MON, TUE, WEN};enum week oneday = 100;printf("%d,Hello, World! \n", oneday); //100,Hello, World! 
}

其实,更正规的做法是进行显式的强制类型转换:

#include <stdio.h>int main()
{	enum week{MON, TUE, WEN};enum week oneday = (enum week)100;printf("%d,Hello, World! \n", oneday); //100,Hello, World! 
}

但是不强制转换也可以,和第一个示例一样,不加的话就是隐式类型转换,不会出错。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

支付宝小程序开发踩坑笔记(支付宝、学习强国小程序)

1、接口请求安卓端回调 success&#xff0c;IOS 端回调 fail 原因&#xff1a;dataType 设置不对&#xff0c;默认是 json 格式&#xff0c;对返回数据会进行 json 解析&#xff0c;如果解析失败&#xff0c;就会回调 fail 。加密传输一般是 text 格式。 2、input 禁止输入空格…

利用tpu-mlir工具将深度学习算法模型转成算能科技平台.bmodel模型的方法步骤

目录 1 TPU-MLIR简介 2 开发环境搭建 2.1 下载镜像 2.2 下载SDK 2.3 创建容器 2.4 加载tpu-mlir 3 准备工作目录 4 onnx转mlir文件 5 mlir转INT8 模型 5.1 生成校准表 5.2 便以为INT8对称量化模型 参考文献&#xff1a; 之前是用nntc转算能科技的模型的&#xff0c…

网易有道BCEmbedding:双语检索与RAG的完美融合

前言 随着人工智能技术的飞速发展&#xff0c;语义表征和检索增强生成&#xff08;Retrieval Augmented Generation, RAG&#xff09;在各个领域的应用日益广泛。在这样的背景下&#xff0c;网易有道推出了划时代的BCEmbedding模型&#xff0c;这不仅是一次技术的革新&#xf…

如何自己实现一个Spring Boot Starter

现在很多开源的组件都会提供对应的 springboot-starter 包给我们去用&#xff0c;要做一个 starter 包并不难。参照Spring内置的实现就好了&#xff1a; 1、在工程里引入 starter 打包相关的依赖。 2、在我们工程内建 spring.factories 文件&#xff0c;编写我们配置类的全限类…

【芯片设计- RTL 数字逻辑设计入门 番外篇6 -- 术语 Tile 介绍】

文章目录 TILE 介绍Tile 的特点Tile 架构的应用Tile 基础架构示例 TILE 介绍 在系统级芯片&#xff08;System on Chip, SoC&#xff09;设计中&#xff0c;“tile” 是一个可以指代不同概念的术语&#xff0c;但通常它指的是芯片上的一个独立的功能单元或核心。一个 tile 可以…

【论文+App试玩+图像到视频】2311.Animate-anyone:上传1张图片为任何人制作动画(用于角色动画的一致且可控的图像到视频合成)(暂未开源)

项目主页&#xff1a;https://humanaigc.github.io/animate-anyone/ 论文: Animate Anyone: Consistent and Controllable Image-to-Video Synthesis for Character Animation 摩尔线程复现代码&#xff1a;https://github.com/MooreThreads/Moore-AnimateAnyone 原作者讲解&am…

【华为 ICT HCIA eNSP 习题汇总】——题目集6

1、IEEE 802.11g 标准支持的最大协商速率为&#xff08;&#xff09;。 A、300Mbps B、150Mbps C、54Mbps D、1200Mbps 考点&#xff1a;无线局域网 解析&#xff1a;&#xff08;C&#xff09; IEEE 802.11系列标准如下表&#xff1a; 标准数据传输速率主要技术IEEE 802.111M…

Wordpress seo优化该怎么做?

Wordpress作为开源管理系统&#xff0c;目前已然是世界上最流行的cms之一&#xff0c;这不仅仅因为他开源&#xff0c;对用户友好&#xff0c;让任何人都能轻而易举的制作网站&#xff0c;更是因为这套程序对于搜索引擎非常友好&#xff0c;是做谷歌seo的不二之选 Wordpress作为…

YOLOv5改进 | Conv篇 | 利用YOLO-MS的MSBlock轻量化网络结构(既轻量又长点)

一、本文介绍 本文给大家带来的改进机制是利用YOLO-MS提出的一种针对于实时目标检测的MSBlock模块(其其实不能算是Conv但是其应该是一整个模块),我们将其用于C2f中组合出一种新的结构,来替换我们网络中的模块可以达到一种轻量化的作用,我将其用于我的数据集上实验,包括多个…

app逆向-frida安装调试

文章目录 一、前言二、安装三、hook调试&#xff0c;hook java类 一、前言 frida是一款基于python javascript 的hook框架&#xff0c;可运行在android ios linux winosx等各平台&#xff0c;主要使用动态二进制插桩技术 官方网站&#xff1a;https://frida.re/docs/home/ a…

绝地求生:PUBG服务条款修订,是否因为PLAYERUNKNOWN礼包导致?

嗨&#xff0c;我是闲游盒~ PUBG全球的官网&#xff0c;刚刚更新了一条《PUBG: 绝地求生》。 通知内容大概如下 对所有平台的PUBG的服务条款进行修订&#xff0c;修订安排于2月7日后生效。 从修订的条款内容猜测&#xff0c;本次修订安排是因为PLAYERUNKNOWN礼包 记得预约荣…

C++ STL之list的使用及模拟实现

文章目录 1. 介绍2. list类的使用2.1 list类对象的构造函数2.2 list类对象的容量操作2.3 list类对象的修改操作2.4 list类对象的访问及遍历操作 3. list类的模拟实现 1. 介绍 英文解释&#xff1a; 也就是说&#xff1a; list是可以在常数范围内在任意位置进行插入和删除的序列…

单点登陆(SSO)基于CAS实现前后端分离的SSO系统开发「IDP发起」

关于其他前端常见登录实现单点登录方案&#xff0c;请见「前端常见登录实现方案 单点登录方案 」 前沿 单点登录&#xff08;SSO&#xff09;&#xff0c;英文全称为 Single Sign On。 SSO 是指在多个应用系统中&#xff0c;用户只需要登录一次&#xff0c;就可以访问所有相互…

macbookpro可以玩什么游戏

最近几年苹果在游戏领域的动作越来越频繁&#xff0c;在当地时间6月6日举行的的WWDC 2023上还请来了小岛秀夫和他的《死亡搁浅导演剪辑版》到现场为苹果电脑站台。事实上&#xff0c;在不久的将来&#xff0c;我们还真有机会看到越来越多Windows上的大作运行在搭载苹果M系列芯片…

旅游项目day14

其他模块数据初始化 搜索实现 请求一样&#xff0c;但是参数不一样&#xff0c;根据type划分。 后台需要提供一个搜索接口。 请求分发器&#xff1a; 全部搜索 目的地搜索 精确搜索、无高亮展示 攻略搜索 全文搜索、高亮显示、分页 游记搜搜 用户搜索 丝袜哥

小程序使用echarts图表-雷达图

本文介绍下小程序中如何使用echarts 如果是通过npm安装&#xff0c;这样是全部安装的&#xff0c;体积有点大 我这边是使用echarts中的一个组件来实现的&#xff0c;下边是具体流程&#xff0c;实际效果是没有外边的红色边框的&#xff0c;加红色边框的效果是这篇说明 1.echa…

什么是网络?

你是一台电脑&#xff0c;你的名字叫 A 很久很久之前&#xff0c;你不与任何其他电脑相连接&#xff0c;孤苦伶仃。 直到有一天&#xff0c;你希望与另一台电脑 B 建立通信&#xff0c;于是你们各开了一个网口&#xff0c;用一根网线连接了起来。 用一根网线连接起来怎么就能&…

【QT+QGIS跨平台编译】之七:【libjpeg+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、libjpeg介绍二、文件下载三、文件分析四、pro文件五、编译实践一、libjpeg介绍 libjpeg是一个广泛使用的jpeg图像压缩和解压的函数库,采用 C 语言开发。 2013年1月,Independent JPEG Group发布了版本9,对新引入的无损编码模式进行了改进。2022年1月,发布了版…

html5实现好看的年会邀请函源码模板

文章目录 1.设计来源1.1 邀请函主界面1.2 诚挚邀请界面1.3 关于我们界面1.4 董事长致词界面1.5 公司合作方界面1.6 活动流程界面1.7 加盟支持界面1.8 加盟流程界面1.9 加盟申请界面1.10 活动信息界面 2.效果和源码2.1 动态效果2.2 源码目录结构 源码下载 作者&#xff1a;xcLei…

《PCI Express体系结构导读》随记 —— 第I篇 第3章 PCI总线的数据交换(1)

前言中曾提到&#xff1a;本章详细阐述了PCI总线的数据传送方式&#xff0c;与Cache相关的内容和预读机制是本章的重点。 PCI Agent设备之间、以及HOST处理器和PCI Agent设备之间可以使用存储器读写和I/O读写等总线事务进行数据传送。在大多数情况下&#xff0c;PCI桥不直接与P…