C语言进阶——chapter5——自定义类型之联合体和枚举

前言

大家好呀,我是Humble,今天继续给大家带来自定义类型的内容

关于自定义类型,有结构体,联合和枚举,上一篇博客我们已经介绍了结构体,不知道大家都掌握了吗

今天我们要分享的内容则是剩下的联合和枚举

接下来,开始今天的分享

0da62ca76f0f42518154d04ade92f852.jpg

一. 联合体

1.联合体类型的声明

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

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

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

下面我们直接看代码

union Un  //这是联合类型的声明
{
 char c;
 int i;
};


int main()
{
 //联合变量的定义
 union Un un = {0};
 //计算联合变量的大小
 printf("%d\n", sizeof(un));

 return 0;
}

代码的运行结果如下:

178fdae2fac94cbab4c41e6e40b431cf.png

为什么结果是4呢?

接下来我们来看一下联合体的特点

2.联合体的特点

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

所以上面的的代码,这个联合体的大小是int的大小为4

接下来我们再看一段代码

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

这个结果是多少呢?

我们打印一下

2f9a9f811a164410af147ec4c98c6b27.png

通过这个代码的输出,我们发现将i的第4个字节的内容修改为55

5c4e8d607b384a80bec343acea85bf40.png

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

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

struct S  //结构体
{
 char c;
 int i;
};

int main()
{
  struct S s = {0};
  return 0;
}

b64aefe44a834774921cbe15013024e3.png

union Un
{
	char c;
	int i;

};

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

0d2dd224d3f4470d8edb837c295fc2be.png

那下面我们来探讨一下联合体的大小该如何计算吧~

4.联合体大小的计算

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

其实,联合体也是存在对齐的

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

请看下面的代码

union Un1
{
	char c[5];  //5
	int i;     //4
};
int main()
{

 printf("%d\n", sizeof(union Un1));

}

是5吗?

我们来打印一下:
25057aee96464411afa9f2ca6246745c.png

这里是8不是5的原因就在于它完成了对齐

i的对齐数是4,因为c是数组,它的对齐数是按其元素来算的,所以对齐数是1

当最大成员大小(这里是5)不是最大对齐数(这里是4)的整数倍的时候,

就要对齐到最大对齐数的整数倍—>所以结果是8,为4的倍数

我们再来看一个

union Un2
{
	short c[7];
	int i;
};
int main()
{

 printf("%d\n", sizeof(union Un2));
 return 0;
}

打印结果如下:

ecd7888333c945979e2f42fd6a3a16c7.png

接下来我们来看一些联合体应用的场景:

比如,我们要搞⼀个活动,要上线一个礼品兑换单,礼品兑换单中有三种商品:

1.图书、2.杯子、3.衬衫

每一种商品都有:库存量价格商品类型和商品类型相关的其他信息

下面是各个商品的商品类型相关的其他信息

图书:书名、作者、页数

杯⼦:设计

衬衫:设计、可选颜色、可选尺寸

下面是理解图:

f78953dff28348a8b75ce01bad7fd937.png

如果我们不耐心思考,直接写出以下结构:

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 un  //联合体
{
    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;

};

5.联合的一个练习

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

我们之前是这么写的

int check_sys()
{
	int n = 1;
	return *(char*)&n;//小端返回1,大端返回0
    
}


int main()
{
	int ret = check_sys();
	if (ret == 1) printf("小端\n");
	else  printf("大端\n");
	return 0;
}

学了联合体后,我们可以这么写:

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

int main()
{
	int ret = check_sys();
	if (ret == 1) printf("小端\n");
	else  printf("大端\n");
	return 0;
}

非常巧妙的写法

二.枚举类型

1.枚举类型的声明和使用

枚举顾名思义就是一一列举。 把可能的取值一一列举

比如:

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

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

3.三原⾊,也是可以一一列举

....

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 Sex的值,我们来打印一下:

40f11a50c2f54e8096257198c25b9b23.png

当然在声明枚举类型的时候也可以赋初值,比如对于enum Color,我们看一下:

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

int main()
{
	printf("%d\n",  RED);
	printf("%d\n",GREENE);
	printf("%d\n",BLUE);

	return 0;
}

f3dfd6afab404ecbaca58717996194d3.png

那我们再来看一下枚举类型的使用:

使用枚举常量给枚举变量赋值

eb99d757012842aebb5cca987fca1d32.png

2.枚举类型的优点

我们前面学过,知道可以使用 #define 定义常量,那我们为什么非要使用枚举?

枚举的优点:

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

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

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

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

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

结语

好了,今天的分享就到这里了

在学习C语言的道路上Humble与各位同行,加油吧各位!

最后希望大家点个免费的赞或者关注吧(感谢感谢),也欢迎大家订阅我的专栏

让我们在接下来的时间里一起成长,一起进步吧!

1d8bd2383fe54a7aa576bdd8d41dc462.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不吃肉的Humble

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值