枚举类型的定义
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,当然在定义的时候也可以赋初值
🌰(默认是从0开始的)
enum Sex//性别 { MALE, FEMALE, SECRET }; int main() { enum Sex sex; //验证默认是从0开始的 printf("%d\n", MALE); printf("%d\n", FEMALE); printf("%d\n", SECRET); return 0; } 运行结果: ***** 0 1 2 *****
🌰(赋值开头)
#include<stdio.h> enum Sex//性别 { MALE = 1, FEMALE, SECRET }; int main() { enum Sex sex; //开头赋值的情况 printf("%d\n", MALE); printf("%d\n", FEMALE); printf("%d\n", SECRET); return 0; } 运行结果: ***** 1 2 3 *****
🌰(中间赋值)
#include<stdio.h> enum Sex//性别 { MALE , FEMALE = 0, SECRET }; int main() { enum Sex sex; //中间赋值的情况 printf("%d\n", MALE); printf("%d\n", FEMALE); printf("%d\n", SECRET); return 0; } 运行结果: ***** 0 0 1 *****
总结:
枚举类型和结构体类型很相似,只过是结构体内部是成员,枚举内部是枚举常量(该类型可能出现的情况)
枚举常量默认是从1依次往下增大的,但是我们也可以赋初值(初始化),但之后就不能改变
.赋初值的位置不同,产生的结果也就不同;在开头赋初值,依次往下递增;在中间赋初值,开头是0,往下递增,赋初值的地方依次往下递增
枚举的优点
其实,在我们不了解枚举类型的情况下,我们一般都是用#define 定义常量,那么枚举类型相比于它又有什么优点呢?
枚举的优点:
1.增加代码的可读性和可维护性
2.和#define定义的标识符比较枚举有类型检查,更加严谨。
3.防止了命名污染(封装)
4.便于调试
5.使用方便,一次可以定义多个常量
🌰(便于调试)
#define MAX 100 //这种情况下,在调试的时候所有的MAX都消失,直接变成100 //且没有#define MAX 100这段代码,不方便调试 enum max { MAX=100, }; //记住枚举是一种类型,在调试的过程中比不会消失,方便调试
🌰(增加代码的可读性与可维护性)
//假如,我们在写一个菜单 //第一种方法: #include<stdio.h> int main() { printf("**************1.add 2.sub************\n"); printf("**************3.mul 4.div************\n"); printf("**************** 0.exit **************\n"); int input = 0; scanf("%d", &input); switch (input) { case 1; break; case 2; break; case 3; break; case 4; break; case 0; break; } //这种情况下,我们会忘记每个数字代表的操作是什么 } //第二种方法: #include<stdio.h> int main() { printf("**************1.add 2.sub************\n"); printf("**************3.mul 4.div************\n"); printf("**************** 0.exit **************\n"); int input = 0; scanf("%d", &input); enum Option { exit, add, sub, mul, dix }; switch (input) { case add; break; case sub; break; case mul; break; case div; break; case exit; break; } //这种情况下,进行的操作和上面的是一样的效果 //但更清楚明了每一步要进行的操作是什么 }
枚举的使用
只能拿枚举常量给枚举变量赋值,才不会出现类型的差异
🌰
#include<stdio.h> enum color { green = 1, red = 5, yellow = 4, blue }; int main() { enum color col = blue; col = 5; //ok??? //虽然blue 和 5 的值是一样的 //但是,第一种情况下直接让col 是blue的值 //而第二种情况下,red跟blue都是5,会产生歧义,而且会产生类型上的差异 return 0; }
联合类型的定义
联合也是一种特殊的自定义类型
这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)
联合的关键字是union
🌰
#include<stdio.h> //联合的声明 union UN { int a; char b; }; int main() { //联合变量的定义 union UN un; //联合变量大小的计算 printf("%d\n", sizeof(un)); return 0; } //运行结果: ***** 4 *****
在这里,我们不禁有一个疑问:
联合的成员在内存中是怎样存储的?
上面例子中,联合变量的大小为什么是4,而不是5?
联合的特点
联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)
🌰
#include<stdio.h> union UN { int a; char b; }; int main() { union UN un; printf("%p\n", &un); printf("%p\n", &(un.a)); printf("%p\n", &(un.b)); return 0; } 运行结果: ***** 012FFC94 012FFC94 012FFC94 *****
从这个例子说明,联合的每次只能单独出现一个出现一个变量,不然的话,进行不同的操作会导致内存紊乱
🐉🐉🐉🐉🐉
那看到这里,不得不提一下联合的一个巧妙用法 ----- 判断当前机器的大小端:
//判断当前机器的大小端 #include<stdio.h> union Clc { char a; int b; }; int main() { union Clc clc; clc.b = 1; if (clc.a == 1) printf("小端\n"); else printf("大端\n"); return 0; }
联合大小的计算
联合的大小至少是最大成员的大小。
当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
🌰
#include<stdio.h> union UN1 { short arr[5]; int b; }; union UN2 { char arr[6]; int b; }; int main() { printf("%d\n", sizeof(union UN1)); printf("%d\n", sizeof(union UN2)); return 0; } //运行结果: ***** 12 8 *****
原因分析:
自定义类型的总结:
结构体的大小存在对其行为
位段的大小不存在对齐行为
枚举的大小就是整形变量的大小,4个字节
联合的大小存在对其行为