017__联合体和枚举
[ 基本难度系数 ]:★☆☆☆☆
一、联合体(共用体)
(1)、基本概念
联合体的外在形式跟结构体非常类似,但它们有一个本质的区别:结构体中的各个成员是各自独立的,而联合体中的各个成员却共用同一块内存,因此联合体也称为共用体。
联合体各成员的堆叠效果
联合体内部成员的这种特殊的“堆叠”效果,使得联合体有如下基本特征:
- 整个联合体变量的尺寸,取决于联合体中尺寸最大的成员。
- 给联合体的某个成员赋值,会覆盖其他的成员,使它们失效。
- 联合体各成员之间形成一种“互斥”的逻辑,在某个时刻只有一个成员有效。
联合体的语法:
联合体标签:用来区分各个不同的联合体。
成员: 是包含在联合体内部的数据,可以是任意的数据类型。
联合体的定义:
union 联合体标签
{
成员1;
成员2;
...
};
(2)、联合体操作
联合体的操作跟结构体形式上别无二致,
- 初始化:
#include <stdio.h>
union node1
{
char ch1;
int num1;
double f1;
char buf1[128];
};
union node2
{
char ch2;
int num2;
};
struct node3
{
int weight;
int height;
int id;
union node1 other;
};
// 主函数
int main(int argc, char const *argv[])
{
// (1)、联合体初始化
// 1、普通初始化(只有第一个成员有效,其它将被覆盖)
union node1 n1 = {'a', 100, 3.14, "shijienameda"};
printf("联合体n1的值: %d\n", n1.num1);
/*
报警告:
001__联合体.c:33:28: warning: excess elements in union initializer
union node1 n1 = {'a', 100, 3.14, "shijienameda"};
^
现象:
打印值为97,而不是100
*/
// 2、指定成员初始化(只有最后一个赋值有效,其它将被覆盖)
union node2 n2 =
{
.num2 = 100,
.ch2 = 'b'
};
printf("联合体n2的值: %d\n", n2.num2);
/*
现象:
打印值为98,而不是100
*/
/*
有兴趣的同学,可以去推敲一下
union node2 n2 =
{
.ch2 = 'b',
.f2 = 3.14,
.num2 = 100 // 内存已经变成了int型性质的内存了, 并赋值了100
};
printf("联合体n2的值: %d\n", n2.f2); // 要求其打印小数数据(S、E、M)
// 打印数据为:1
*/
return 0;
}
- 联合体成员引用(直接使用):
at.x = 100;
at.y = 'k';
at.z = 3.14; // 只有最后一个赋值的成员有效
printf("%d\n", at.x);
printf("%c\n", at.y);
printf("%lf\n", at.z);
- 联合体成员引用(直接使用):
at.x = 100;
at.y = 'k';
at.z = 3.14; // 只有最后一个赋值的成员有效
printf("%d\n", at.x);
printf("%c\n", at.y);
printf("%lf\n", at.z);
- 联合体指针(间接使用):
union attr *p = &at;
p->x = 100;
p->y = 'k';
p->z = 3.14; // 只有最后一个赋值的成员有效
printf("%d\n", p->x);
printf("%c\n", p->y);
printf("%lf\n", p->z);
(3)、联合体的使用
联合体一般很少单独使用,而经常以结构体的成员形式存在,用来表达某种互斥的属性。
- 示例:
struct node
{
int a;
char b;
double c;
union attr at; // at内有三种互斥的属性,非此即彼
};
int main()
{
struct node n;
n.at.x = 100; // 使用连续的成员引用符来索引结构体中的联合体成员
}
二、枚举
枚举类型的本质是提供一种范围受限的整型,比如用0-6表示七种颜色,用0-3表示四种状态等,但枚举在C语言中并未实现其本来应有的效果,直到C++环境下枚举才拥有原本该有的属性。
- 枚举常量列表
- enum是关键字
- spectrum是枚举常量列表标签,可以省略。省略的情况下无法定义枚举变量
enum spectrum{red, orange, yellow, green, blue, cyan, purple};
enum {reset, running, sleep, stop};
- 枚举变量
enum spectrum color = orange; // 等价于 color = 1
- 语法要点:
- 枚举常量实质上就是整型,首个枚举常量默认为0。
- 枚举常量在定义时可以赋值,若不赋值,则取其前面的枚举常量的值加1。
- C语言中,枚举等价于整型,支持整型数据的一切操作。
- 使用举例:
switch(color)
{
case red:
// 处理红色...
case orange:
// 处理橙色...
case yellow:
// 处理黄色...
}
- 枚举数据最重要的作用,是使用有意义的单词,来替代无意义的数字,提高程序的可读性。
- 示例代码:
#include <stdio.h>
// stm32的枚举的使用
/**
* @brief STM32F4XX Interrupt Number Definition, according to the selected device
* in @ref Library_configuration_section
*/
typedef enum
{
/****** Cortex-M4 Processor Exceptions Numbers ****************************************************************/
NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */
MemoryManagement_IRQn = -12, /*!< 4 Cortex-M4 Memory Management Interrupt */
BusFault_IRQn = -11, /*!< 5 Cortex-M4 Bus Fault Interrupt */
UsageFault_IRQn = -10, /*!< 6 Cortex-M4 Usage Fault Interrupt */
SVCall_IRQn = -5, /*!< 11 Cortex-M4 SV Call Interrupt */
DebugMonitor_IRQn = -4, /*!< 12 Cortex-M4 Debug Monitor Interrupt */
PendSV_IRQn = -2, /*!< 14 Cortex-M4 Pend SV Interrupt */
SysTick_IRQn = -1, /*!< 15 Cortex-M4 System Tick Interrupt */
/****** STM32 specific Interrupt Numbers **********************************************************************/
WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */
PVD_IRQn = 1, /*!< PVD through EXTI Line detection Interrupt */
TAMP_STAMP_IRQn = 2, /*!< Tamper and TimeStamp interrupts through the EXTI line */
RTC_WKUP_IRQn = 3
} IRQn_Type;
enum color // 有类型,所以能定义变量
{
red, // 没有赋值默认是0
orange, // 会接上上面的值+1 == 1
yellow, // == 2
green = 15, // 赋值了,所以是15
blue, // 会接上上面的值+1 == 16
cyan, // == 17
purple // == 18
};
// 表示状态
enum // 没有类型,所以不能定义变量
{
reset, // 重启
running, // 运行
sleep, // 睡眠
stop // 停止
};
int main(int argc, char const *argv[])
{
// (1)、枚举类型默认初始化
// 1、默认不初始化(枚举类型本质就是一个整型)
enum color c ; // 默认为0,也有可能是乱码(看编译器)
printf("c = %d\n", c);
// 2、初始化
enum color a = 1;
printf("a = %d\n", a);
enum color b = yellow;
printf("b = %d\n", b);
printf("orange = %d\n", orange); // red颜色默认是0,后面加1,就是1
printf("blue = %d\n", blue); // green颜色是15,后面加1,就是16
// (2)、在实际开发中使用(是使用有意义的单词,来替代无意义的数字,提高程序的可读性。)
// 1、颜色选择
enum color c_color;
printf("请输入颜色数据:\n");
printf("0、红色\n");
printf("1、橙色\n");
printf("2、黄色\n");
scanf("%d", (int*)&c_color);
while(getchar()!='\n');
switch (c_color)
{
case red:
printf("我是红色\n");
break;
case orange:
printf("我是橙色\n");
break;
case yellow:
printf("我是黄色\n");
break;
default:
printf("我没有色\n");
break;
}
// 2、机器状态选择
int robot_status = stop;
if (robot_status == stop)
{
printf("现在这个机器是停止状态\n");
}
return 0;
}