目录
在上篇文章中已经介绍了结构体。另外,C语言还提供了另外两种数据类型——联合体(union)和枚举(enum),它们各自具有独特的功能和用途。本文将带你深入了解联合体和枚举的概念、用法以及它们在实际编程中的应用。
一.联合体
像结构体⼀样,联合体也是由⼀个或者多个成员构成,这些成员可以不同的类型。
但是编译器只为最⼤的成员分配⾜够的内存空间。联合体的特点是所有成员共⽤同⼀块内存空间。
所以联合体也叫:共⽤体。 给联合体其中⼀个成员赋值,其他成员的值也跟着变化。
1.1 联合体的声明
union Un
{
char c;
int i;
};
1.2 联合体的使用
#include <stdio.h>
//联合类型的声明
union Un
{
char c;
int i;
};
int main()
{
//联合变量的定义
union Un un = {0};
//计算连个变量的⼤⼩
printf("%d\n", sizeof(un));
return 0;
}
输出结果:4
1.3 为什么输出 4呢?
int类型的大小通常是4个字节(byte)。由于联合体的大小至少足够大以容纳其最大的成员,因此Un联合体的大小至少应该是int类型的大小,所以输出为 4。
代码1:
#include <stdio.h>
//联合类型的声明
union Un
{
char c;
int i;
};
int main()
{
//联合变量的定义
union Un un = {0};
// 下⾯输出的结果是⼀样的吗?
printf("%p\n", &(un.i));
printf("%p\n", &(un.c));
printf("%p\n", &un);
return 0;
}
输出结果:
012FFD0C
012FFD0C
012FFD0C
这段代码输出了三个地址,它们分别是联合体Un的int成员i的地址、char成员c的地址,以及整个联合体变量un的地址。
代码2:
#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;
}
输出结果:
11223355
un.i赋值0x11223344,这是一个十六进制数,它会被存储在un联合体所分配的内存中。因为int类型通常占用4个字节,所以0x11223344会被完整地存储在这4个字节中。
然后,代码又对un.c赋值0x55。由于un.c和un.i共享同一块内存,这个赋值会覆盖un.i的最低有效字节(即char类型所占用的字节)。
那么,0x55会覆盖0x11223344的最低字节,变成0x11223355
最后,代码打印un.i的值,由于我们已经修改了它的最低字节,所以输出的是11223355。(小端机器)。
1.4 相同成员的结构体和联合体对比
代码示例:
struct S
{
char c;
int i;
};
struct S s = { 0 };
union Un
{
char c;
int i;
};
union Un un = { 0 };
1.5 联合体大小对比
• 联合的大小至少是最⼤成员的⼤⼩。
• 当最大成员大小不是最⼤对⻬数的整数倍的时候,就要对齐到最大对齐数的整数倍。
代码示例:
#include <stdio.h>
union Un1
{
char c[5];
int i;
};
union Un2
{
short c[7];
int i;
};
int main()
{
//下⾯输出的结果是什么?
printf("%d\n", sizeof(union Un1));
printf("%d\n", sizeof(union Un2));
return 0;
}
输出结果:
8
16
由于 char 数组的大小是5个字节,而 int 通常需要4字节对齐,编译器可能会选择增加1个字节的填充(padding),使得整个 union Un1 的大小为8个字节,以满足 int 的对齐要求。
short c[7] 需要14个字节,这超过了 int 的4个字节,所以 union Un2 的大小将是14个字节。与 union Un1 类似,由于内存对齐的原因,编译器可能会增加额外的填充。在这种情况下,编译器可能会添加2个字节的填充,使 union Un2 的总大小为16个字节。
使用联合体可以节省空间。
1.6使用联合体判断大小端
代码示例:
#include <stdio.h>
int check_sys()
{
union
{
int i;
char c[sizeof(int)]; // 使用字符数组以便访问int的各个字节
} un;
un.i = 1; // 设置int为1
// 检查int的最低有效字节(在小端系统中应该是1)
return *(char *)&un.i == 1; // 如果返回true(非零),则是小端系统;如果返回false(零),则是大端系统
}
int main()
{
if (check_sys()) {
printf("这是一个小端系统。\n");
} else {
printf("这是一个大端系统。\n");
}
return 0;
}
二.枚举类型
枚举类型(enum)是一种用户定义的数据类型,枚举(enum)顾名思义就是⼀⼀列举。把可能的取值⼀⼀列举。
2.1枚举类型的例举:
例如:
一周的星期⼀到星期日是有限的7天,可以一一列举
//星期
enum Weekday
{
Sunday,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
};
性别有:男、女、保密,也可以一一列举
//性别
enum Sex
{
Male,
Female,
Cfidntl
};
2.2枚举类型的优点
1. 增加代码的可读性和可维护性
2. 和#define定义的标识符⽐较枚举有类型检查,更加严谨。
3. 便于调试,预处理阶段会删除 #define 定义的符号
4. 使方便便,一次可以定义多个常量
5. 枚举常量是遵循作用域规则的,枚举声明在函数内,只能在函数内使用
2.3 枚举类型的使用
#include <stdio.h>
enum Color
{
Red,
Green,
Blue,
};
int main()
{
// 声明一个Color类型的变量
enum Color myColor;
myColor = Red;
switch (myColor) {
case Red:
printf("颜色是红色。\n");
break;
case Green:
printf("颜色是绿色。\n");
break;
case Blue:
printf("颜色是蓝色。\n");
break;
default:
printf("未知的颜色。\n");
break;
}
return 0;
}
注意,在C语言中,枚举常量默认从0开始,并且每个后续常量比前一个常量大1。因此,在这个例子中,Red的值为0,Green的值为1,Blue的值为2
当然也以拿整数给枚举变量赋值。在C语⾔中是可以的,但是在C++是不行的,C++的类型检查⽐ 较严格。
代码示例:
enum Color
{
Red = 1,
Green = 2,
Blue = 3
};