C语言自定义类型(下)

大家好,我们今天来学习C语言自定义类型剩下的内容。
在这里插入图片描述

目录

1.枚举
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 都是枚举类型。
{}中的内容是枚举类型的可能取值,也叫 枚举常量 。

那么我们的枚举常量的值又是多少呢?

enum Sex
{
	//枚举的可能取值
	MALE,//枚举常量
	FEMALE,
	SECRET
};
enum Color
{
	RED,
	GREEN,
	BLUE
};

int main()
{

	printf("%dn", MALE);
	printf("%dn", FEMALE);
	printf("%dn", SECRET);
	enum Sex sex = SECRET;

	printf("%zdn", sizeof(sex));

	return 0;
}

在这里插入图片描述

这是因为这些可能取值都是有值的,默认从0开始,一次递增1,当然在定义的时候也可以赋初值。

例如:

enum Sex
{
	//枚举的可能取值
	MALE=3,//枚举常量
	FEMALE,
	SECRET
};
int main()
{
	//MALE = 5;//ERR
	printf("%dn", MALE);
	printf("%dn", FEMALE);
	printf("%dn", SECRET);
	enum Sex sex = SECRET;

	printf("%zdn", sizeof(sex));

	return 0;
}

在这里插入图片描述

这里我们给它赋初值,我们给MALE赋值为3,后面的值就会默认加1,所以打印的结果就为3,4,5。

我们不仅可以这么定义,而且我们可以用宏来进行赋值定义:

#define MALE 3
#define FEMALE 4
#define SECRET 5

那么我们最好还是用枚举,那这是为什么呢,只就得提到我们枚举的优点了:

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

  1. 增加代码的可读性和可维护性
  2. 和#define定义的标识符比较枚举有类型检查,更加严谨。
  3. 防止了命名污染(封装)
  4. 便于调试
  5. 使用方便,一次可以定义多个常量

当我们使用枚举时只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。
例如下面的代码:

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

相信大家应该都已经了解了枚举的应用,那么我们就进入下个内容的学习。

2.联合(共用体)

联合类型的定义:

联合也是一种特殊的自定义类型
这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)。

//联合类型的声明
union Un
{
	char c;
	int i;
};
//联合变量的定义
int main()
{
	union Un un;
	//计算连个变量的大小
	printf("%dn", sizeof(un));
	return 0;
}

在这里插入图片描述

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

int main()
{
	union Un un;
	//printf("%dn", sizeof(un));
	printf("%pn", &un);
	printf("%pn", &(un.c));
	printf("%pn", &(un.i));

	return 0;
}

在这里插入图片描述

我们发现整个联合体的大小是4个字节,而我们定义的int型变量i就是4个字节,那么我们是不是就可以间接的认为联合体是公用一个空间一个内存的呢?我们再看到我们对整个联合体变量取地址和分别对联合体的成员变量取地址,打印出来发现它们的地址是一样的,这就可以说明联合体是公用一段内存的。

联合的特点

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

还记得之前我们如何判断大端还是小端的题吗?这里我们就可以利用联合体来解决:

int check_sys()
{
	int a = 1;
	if (*(char*)&a == 1)//int*
		return 1;
	else
		return 0;
}

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

	return 0;
}

在这里插入图片描述

在这里插入图片描述

我们的小端是从低地址到高地址的,所以我们给a取出一个字节就是先给它强制转换为char型在解引用,如果等于1那么就是小端,如果不是1那就是大端。

联合大小的计算

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

union Un
{
	char c[5];//5
	int i;//4
};

int main() 
{
	printf("%zdn", sizeof(union Un));

	return 0;
}

在这里插入图片描述

union Un
{
	short c[7];//14
	int i;//4
};

int main()
{
	printf("%zdn", sizeof(union Un));

	return 0;
}

在这里插入图片描述

我们看到第一个代码因为char型的大小是一个字节,和vs默认的8个对齐数相比更小,所以它的对齐数是1,而int型的大小是4个字节,和vs默认的8个对齐数相比也小,所以它的对齐数就是4,而c是个字符类型的数组,占了5个字节,i只占了4个字节,因为联合的大小至少是最大成员的大小。当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。所以我们联合体的大小就是8个字节。而第二个代码也是这么计算,得出来的就是16个字节。

好了今天的学习就到这里了,感谢大家的支持,我们下次再见。