1. 枚举
一一列举
一周七天
一年四季
一年十二个月
a. 枚举类型的定义
// 枚举类型
enum Season
{
// 枚举的可能取值--常量
SPRING,
SUMMER,
AUTUMN,
WINTER
};
注意,枚举类型的取值,用逗号隔开,最后一个后面没有逗号
使用
enum Season s = SPRING;
- 默认的值是第一个
SPRING
为0,依次递增1,2,3- 有时候可能觉着默认的是0不合适,我们可以写成
SPRING = 3, SUMMER = 6,...
改成自己想要的值。- 对于不赋值的常量,是根据上一个常量递增得到的。比如
SPRING = 2,SUMMER,AUTUMN = 8
此时的SUMMER
的值就是3
b. 枚举的优点
我们也可以使用#define
定义常量,那为什么使用枚举呢
- 增加代码的可读性和可维护性
- 和
#define
定义的标识符比较,枚举有类型检查,更加严谨
- 比如
#define SPRING 0
- 这里的SPRING就是一个符号,没有类型
- 而在枚举类里面是有类型的
- 防止了命名污染(封装)(命名冲突)
- 便于调试
- 使用方便,一次可以定义多个常量
2. 联合
a. 联合类型的定义
也是一种特殊的自定义类型,这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)。比如:
union Un
{
char c;
int i;
};
union Un u;
// 计算 u 所占空间的大小
printf("%d\n", sizeof(u)); // 4
// 打印联合体中 u 和其变量地址
// 发现这三个地址值一模一样
printf("%p\n", &u);
printf("%p\n", &(u.c));
printf("%p\n", &(u.i));
b. 联合的特点
联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)
之前有讲过如何判断当前计算机的大小端存储。
int a = 0x11223344;
// 低地址 --------> 高地址
// 11 22 33 44 大端存储
// 44 33 22 11 小端存储
// 如何判断大端小端?
int a = 1; // ---> 0x 00 00 00 01 存储到内存
// 如果是 01 00 00 00 就是小端
// 如果是 00 00 00 01 就是大端
// 因此只要判断第一个字节是00 还是 01就行
// 所以只要取到这个地址,向后访问一个字节就行,但是int类型加1是加4个字节,如何取到呢???
// 所以一种办法是将这个 a 强转成字符指针
if (*(char*)&a == 1)
{
// 小端
}else{
// 大端
}
另一种实现方式是
union Un
{
char c; // 1个字节
int i; // 4个字节
}
// 我们可以巧妙应用这个结构
// 当往里面给 i 存储 1的时候,查看 c的值就行
u.i = 1;
if (u.c == 0)
{
// 大端
}else{
// 小端
}
c. 联合大小的计算
-
联合的大小至少是最大成员的大小
-
当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
union Un { int a; // 4 对齐数是4 char arr[5]; // 5 对齐数不是按照数组大小,是数组元素大小,对齐数是1 };
所以这个联合体的大小是4的整数倍!!!又要包含arr[5]这么大的空间,所以结果是8