C语言自定义类型-----枚举、联合体

目录

1、枚举

1.1 枚举类型的定义 

1.2 枚举的优点

1.3 枚举的使用

2、联合体 

2.1 联合体类型

2.2 联合体变量的初始化

2.3 联合体大小的计算 


1、枚举

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

比如我们现实生活中:一周的星期一到星期日是有限的 7 天,可以一 一列举。 

凡是生活中可以一 一列举出来的,就可把这些值它们对应的类型就可以定义成枚举类型。 枚举类型就是一种类型,这是我们要注意的,就像结构体类型一样都是属于自定义类型的。

1.1 枚举类型的定义 

枚举类型定义的关键字是:enum 。定义枚举类型的语句格式为:

enum 枚举类型名
{
    //枚举的可能取值--枚举常量
};

如:

enum Day//星期
{
	Mon,//枚举的可能取值
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun
};
以上定义的 enum Day 就是枚举类型了。{ }中的内容是枚举类型的可能取值,也叫 枚举常量 。 这些可能取值都是有值的,默认从 0 开始,一次递增 1。 如:
#include<stdio.h>

enum Day//星期
{
	Mon,//枚举的可能取值
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun
};

int main()
{
	printf("枚举常量值如下:\n");
	printf("Mon = %d\n", Mon);
	printf("Tues= %d\n", Tues);
	printf("Wed = %d\n", Wed);
	printf("Thur= %d\n", Thur);
	printf("Fri = %d\n", Fri);
	printf("Sat = %d\n", Sat);
	printf("Sun = %d\n", Sun);
	return 0;
}

运行结果:

当然在定义的时候也可以赋初值,给一个枚举常量赋初值时,就会接连的改变后面的枚举常量的默认值。 如:
#include<stdio.h>

enum Day//星期
{
	Mon,//枚举的可能取值
	Tues,
	Wed = 66,
	Thur,
	Fri,
	Sat = 88,
	Sun
};

int main()
{
	printf("枚举常量值如下:\n");
	printf("Mon = %d\n", Mon);
	printf("Tues= %d\n", Tues);
	printf("Wed = %d\n", Wed);
	printf("Thur= %d\n", Thur);
	printf("Fri = %d\n", Fri);
	printf("Sat = %d\n", Sat);
	printf("Sun = %d\n", Sun);
	return 0;
}

Mon 的默认值为 0、Tues 的默认值为  1,给枚举常量赋初值 Wed = 66,那么在 Wed 后的枚举常量  Thur 的默认初值变为 67,Fri 的默认初值变为 68。以此类推,给枚举常量赋初值 Sat = 88,那么在 Sat 后的枚举常量  Sun 的默认初值变为 89;运行结果如下:

 

总结:当给一个枚举常量赋初值时,就会相应的改变后面的枚举常量的默认初值

注意:给枚举常量赋初值, 不是改变枚举常量(常量是不能改变的),而是给这个常量赋一个初始值,即使他是常量,他也应该有一个值,既然我们不想让它有其他的默认的初始值,就可以自定义的给它一个初始值。

1.2 枚举的优点

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

1.3 枚举的使用

(1)

#include<stdio.h>

enum Day//星期
{
	Mon,//枚举的可能取值--枚举常量
	Tues,
	Wed,
	Thur,
	Fri,
	Sat = 66,//给常量赋初始值,就相当于与常量 const int num = 88;这是一个常量,给它赋初始值,而不是改变它
	Sun
};

int main()
{
	enum Day day = Mon;//只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。
	enum Day temp = 66;//此种写法是不推荐的,因为存在类型差异。原因:66 是int类型,temp是枚举类型。
	//Sat = 88;//这是错误的,Sat 是一个常量,不能改变的
    printf("%d", sizeof(day));//enum Day枚举类型的大小为一个整型的大小,也就是:4 个字节。原因:只能拿一个枚举常量给枚举变量赋值,枚举常量是一个整型。
	return 0;
}

 (2)

#include<stdio.h>

//定义枚举类型
enum Day//星期
{
	exit,//枚举的可能取值--枚举常量
	Mon,
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun
};

void menu()
{
	printf("-----------------------------\n");
	printf("-----1.Mon    2.Tues---------\n");
	printf("-----3.Wed    4.Thur---------\n");
	printf("-----5.Fri    6.Sat----------\n");
	printf("-----7.Sun    0.exit---------\n");
	printf("-----------------------------\n");
	printf("请输入你的选择:> ");
}

int main()
{
	int input = 0;
	do
	{
		menu();
		scanf("%d", &input);
		switch (input)
		{
		case Mon:
			printf("星期一\n");
			break;
		case Tues:
			printf("星期二\n");
			break;
		case Wed:
			printf("星期三\n");
			break;
		case Thur:
			printf("星期四\n");
			break;
		case Fri:
			printf("星期五\n");
			break;
		case Sat:
			printf("星期六\n");
			break;
		case Sun:
			printf("星期日\n");
			break;
		case exit:
			printf("退出\n");
			break;
		default:
			printf("选择错误\n");
			break;
		}
	} while (input);
	return 0;
}

总结:只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。

2、联合体 

定义不同数据类型的数据共占同一段内存空间,以满足某些特殊的数据处理要求,这种数据构造类型就是联合体。 

2.1 联合体类型

联合体也是一种构造数据类型,和结构体类型一样,它也是由各种不同类型的数据组成,这些数据叫做联合体的成员。和结构体不同的是,在联合体中,C 语言编译系统使用了覆盖技术,使联合体的所有成员在内存中具有相同的首地址,共占同一段内存空间,这些数据可以相互覆盖,因此联合体也常常被称做是共用体,在不同的时间保存不同的数据类型和不同长度的成员的值。也就是说,在某一时刻,只有最新存储的数据是有效的。运用此种类型数据的优点是节省存储空间。

联合体类型定义的一般形式为: 

union 联合体名
{
    数据类型 1 成员名 1;
    数据类型 2 成员名 2;
    ......
    数据类型 n 成员名 n;
};

union 是 C 语言中的关键字,表明是在进行一个联合体类型的定义。联合体类型名是一个合法的 C 语言标识符,联合体类型成员的数据类型可以是 C 语言中的任何一个数据类型,最后的分号表示联合体定义的结束。如:

union ucode
{
    char u1;
    int u2;
    long u3;
};

 这里定义了一个名为 union ucode 的联合体类型,它包括 3 个成员,分别是字符型、整型和长整型。

说明:联合体类型的定义只是由用户构造了一个联合体,定义好后可以像 C 中提供的基本数据类型一样使用,即可以用它来定义变量、数组等。但定义联合体类型时,系统并不为其分配存储空间,而是为由该联合体类型定义的变量、数组等分配存储空间。 

联合体变量的定义和结构体变量的定义一样,也是三种方法,这里就不多说了。 

2.2 联合体变量的初始化

定义联合体变量的同时对其成员赋初值,就是对联合体变量的初始化。那么,对联合体变量初始化可以和结构体变量一样,在定义时直接对其各个成员赋初值吗? 如:

union ucode
{
    char u1;
    int u2;
};//定义联合体类型

union ucode a = {'a',45};//定义联合体类型的变量 a 并初始化(错误的)

union ucode a = {'a',45}  定义联合体类型的变量 a 并初始化,这是错误的形式。原因:这是因为联合体和结构体变量的存储结构不同,联合体变量中的成员是共用一个首地址,共占同一段内存空间,所以在任意时刻只能存放其中一个成员的值。也就是说,每一瞬时只能有一个成员起作用,所以,在对联合体类型的变量定义并初始化时,只能是对第 1个成员赋初值,初值需要用 “ { } ” 括起来。

联合体变量的引用 :

联合体变量不能整体引用,对联合体变量的赋值、使用都只能对变量的成员进行。联合体变量引用其成员的方法与访问结构体变量成员的方法相同。

2.3 联合体大小的计算 

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

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

如: 

#include<stdio.h>

union Un1
{
	char c[5];//char 1个字节-->默认对齐数为 8 --> 1 比 8 小--> 对齐数为 1
	int i;//int 4 个字节 --> 默认对齐数为 8 --> 4 比 8 小--> 对齐数为 4-->为该联合体的最大对齐数
	//最大是5字节,5不是最大对齐数的整数倍,就要对齐到最大对齐数的整数倍,也就是 8
};
union Un2
{
	short c[7];//14个字节	short 2个字节 --> 默认对齐数为 8 --> 2 比 8 小--> 对齐数为 2
	int i;//4个字节		int 4 个字节 --> 默认对齐数为 8 --> 4 比 8 小--> 对齐数为 4 --> 为该联合体的最大对齐数
	//最大的是14个字节,14不是最大对齐数的整数倍,就要对齐到最大对齐数的整数倍,也就是 16
};
int main()
{
	//下面输出的结果是什么?
	printf("%d\n", sizeof(union Un1));
	printf("%d\n", sizeof(union Un2));
	return 0;
}

运行结果:

最后来看一道面试题: 判断当前计算机的大小端存储  

什么是大小端字节序呢?也就是一个数据,存放在内中的存放的字节顺序。

把一个数存储到内存中,高字节的内容存放到低地址的,低字节的内容放在高地址的,就叫是大端字节序存储模式;低字节的内容存放到低地址的,高字节的内容放在高地址的,就叫是小端字节序存储模式如下图:

(1)利用指针

//int a = 0x11223344;//int a=1;//0x00 00 00 01
//    低地址------------>高地址
//----[][][][][11][22][33][44][][][][][][][]----把一个数的高字节的内容存放到低地址的,低字节的内容放在高地址的,就叫是大端字节序存储模式
//----[][][][][44][33][22][11][][][][][][][]----把一个数的低字节的内容存放到低地址的,高字节的内容放在高地址的,就叫是小端字节序存储模式
//讨论一个数据,存放在内中的存放的字节顺序
//大小端字节序问题
#include<stdio.h>

int main()
{
	int a = 1;
	char* pchar = (char*)&a;
	if (*pchar == 1)
	{
		printf("字节序存储模式是小端\n");
	}
	else
	{
		printf("字节序存储模式是大端\n");
	}
	return 0;
}

(2)利用联合体

#include<stdio.h>

int check_sys()
{
	union Un
	{
		char c;
		int i;
	}u;
	u.i = 1;
	//返回1,表示小端
	//返回0,表示大端
	return u.c;
}

int main()
{
	int ret = check_sys();
	if (ret == 1)printf("小端\n");
	else printf("大端\n");
	return 0;
}
  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值