联合与枚举

自定义类型有三种:结构体,联合体,枚举。

结构体已经讲解完了,接下来我们学习联合体和枚举。

一.联合体

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

结构体使用struct,而联合体使用union。

那么结构体和联合体由什么关系呢?

结构体联合体
structunion
多个成员多个成员
每个成员都有自己独立的空间所有成员公用同一块内存空间

所以联合体也可以叫做:共用体。

union Un
{
	char c;//1
	int i; //4
};

假设有这样一个联合体,那么思考一下,这个联合体的大小是多少呢?

	union Un u = {0};
	printf("%zd\n", sizeof(u));//4

	printf("%p\n", &u);
	printf("%p\n", &(u.i));
	printf("%p\n", &(u.c));

答案是4。

而且联合体u,和i,c的地址是一模一样的,说明i和c的空间是由重叠的。

这是因为联合体的所有成员是共用同一块内存空间的,所以编译器只会为最大的成员分配足够的内存空间。也正是因为他们公用同一个空间,给其中一个成员进行赋值,是会改变其他成员的值的。

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

 i和c公用一个空间,c是占据在i的第一个字节的。un.i = 0x11223344.0x开头的数字是十六进制的。根据小端存储,i的第一个字节到第四个字节存的分别是44,33,22,11.un.c = 0x55,所以也就是将第一个字节的改成55.%x是以十六进制打印数字。所以打印出来就是0x11223355.

 联合体大小的计算

  1. 联合体的大小至少是最大成员的大小。
  2. 当最大成员的大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍处。 
#include <stdio.h>
union Un1
{
 char c[5];
 int i;
};
union Un2
{
 short c[7];
 int i;
};
int main()
{
 //下⾯输出的结果是什么?
 printf("%zd\n", sizeof(union Un1));
 printf("%zd\n", sizeof(union Un2));
 return 0;
}

union Un1的最大成员大小是5个字节,但是最大对齐数是4,要对齐到4的整数倍处,所以输出结果是8.

union Un2的最大成员大小是2 * 7 = 14个字节,但是最大对齐数是4,要对齐到4的整数倍处,所以输出结果是16.

在union Un1 中,i和c的地址是一样的。同理在union Un2 中也是如此。

联合体的举例使用

比如,我们要搞一个活动,要上线一个礼品兑换单,礼品兑换单中有三个商品:图书,杯子,衬衫。

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

  1. 图书:书名,作者,页数。
  2. 杯子:设计。
  3. 衬衫:设计,可选颜色,可选尺寸。

联合体的特性是,在使用其中一种成员变量的时候,其他的成员变量是不能使用的,不然数据就会被覆盖。

假如我们使用结构体来定义这个礼品兑换单,我们就会发现有些成员变量是用不到的,这样的话就会造成内存浪费。

所以我们可以使用结构体。

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 check_sys()
{
	union
	{
		int i;
		char c;
	}un;
	un.i = 1;//0x00 00 00 01
	//c占据的一个字节就是i的第一个字节
	//如果返回值是1,小端字节序。
	//如果返回值是0,大端字节序。
	return un.c;
}

二.枚举 

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

比如我们现实生活中:

一周的星期一到星期天,可以一一列举。

月份也可以一一列举。

这样的数据的表示都可以一一列举。 

enum Week{Mon,Tues,Wednes,Thur,Fri,Satur,Sun};

enum Color {RED,GREEN,BLUE};

以上定义的enum Week,enum Color均是枚举类型。{}中的内容都是枚举类型的可能取值,也叫做枚举常量

这些枚举常量都是有值的

 

这些枚举常量都是有值的,在默认情况下,第一个枚举常量的值是0,从左向右依次加1.

当然这些枚举常量在声明的情况下也是可以赋初值的。 

在赋值后,右边的值也会跟着改变,Wednes变成了6,右边的值是是其左边的数的值加1,这是默认不变的。

 为什么要使用枚举呢?

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

枚举的优点:

  1. 增加代码的可读性和可维护性
  2. 和#define相比,有类型的检查,更加严谨
  3. 便于调试,预处理阶段会删除#define定义的符号,将其全部替换
  4. 方便使用,一次性可定义多个常量
  5. 枚举常量是遵循作用域规则的,枚举的声明在函数内的话,就只能在函数内部使用。
#include<stdio.h>
int main() {
	enum Week { Mon = 1, Tues = 5, Wednes, Thur, Fri, Satur, Sun };
	enum Week day = Mon;
	printf("%d ", day);
	day = 2;
	printf("%d ",day);
}

在C语言中,是可以拿整数给枚举变量进行赋值的,但是在C++中是不行的,C++的类型检查比较严格。

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值