C语言中的共用体是一种特殊数据类型,它允许在同一内存中存储不同的数据类型。共用体的大小为其中最大成员的大小。
共用体的定义使用 union 关键字:
// 定义共用体类型
union 共用体类型名
{
类型 变量名1;
类型 变量名2;
类型 变量名3;
// ...
};
// 定义共用体类型的变量
struct 共用体类型名 变量名;
通过共用体类型的变量访问其内部成员时,使用 . 运算符;通过共用体指针类型的变量访问其内部成员时,使用 -> 运算符。
示例:
#include <stdio.h>
#include <stdbool.h>
// 定义枚举,表示事件类型
enum EventType
{
QUIT_EVENT,
KEY_EVENT,
// ... 其它事件类型
};
// 定义结构体,表示退出事件的具体信息
struct QuitEvent
{
enum EventType type; // 事件类型,为 QUIT_EVENT
};
// 定义结构体,表示按键事件的具体信息
struct KeyEvent
{
enum EventType type; // 事件类型,为 KEY_EVENT
int key; // 按键编码
bool press; // 按下还是松开
};
// 定义共用体类型
union Event
{
enum EventType type; // 事件类型
struct QuitEvent quit; // 退出事件的信息
struct KeyEvent key; // 按键事件的信息
};
int main(void)
{
printf("union Event 的大小为 %zu 字节\n", sizeof(union Event));
printf("enum EventType 的大小为 %zu 字节\n", sizeof(enum EventType));
printf("struct QuitEvent 的大小为 %zu 字节\n", sizeof(struct QuitEvent));
printf("struct KeyEvent 的大小为 %zu 字节\n", sizeof(struct KeyEvent));
// 定义事件变量
union Event event;
// 编辑事件内容
event.type = KEY_EVENT; // 事件类型为按键事件
event.key.key = 'A'; // 按键为 A
event.key.press = true; // 按键被按下
// 解析事件
switch (event.type)
{
case QUIT_EVENT:
printf("退出事件\n");
break;
case KEY_EVENT:
printf("按键事件, '%c', %s\n", event.key.key, event.key.press ? "按下" : "松开");
break;
default:
printf("未知事件\n");
break;
}
return 0;
}
运行结果:
union Event 的大小为 12 字节
enum EventType 的大小为 4 字节
struct QuitEvent 的大小为 4 字节
struct KeyEvent 的大小为 12 字节
按键事件, 'A', 按下
这个示例中通过共用体实现了事件类型 union Event,包含成员 type,quit,key;其中 key 最大,为 12 字节,因此 union Event 的大小为 12 字节。
这里 union Event、struct QuitEvent、struct KeyEvent 采用了相同的内存布局,即第一个字段都是 int type,用于保存事件类型。
在获取事件(union Event)后读取 type 字段判断事件类型,然后根据事件类型,采用不同的字段(quit 和 key)来解析事件内容。
flowchart TB
subgraph subGraph0["struct QuitEvent"]
qe0["type"]
end
subgraph subGraph1["struct KeyEvent"]
ke0["type"]
ke1["key"]
ke2["press"]
end
subgraph subGraph2["union Event"]
e0["type"]
subGraph0
subGraph1
end
e0 --> qe0 --> ke0
style qe0 stroke:#00C853,fill:#C8E6C9
style ke0 stroke:#00C853,fill:#C8E6C9
style ke1 stroke:#00C853,fill:#C8E6C9
style ke2 stroke:#00C853,fill:#C8E6C9
style e0 stroke:#AA00FF,fill:#E1BEE7
style subGraph0 stroke:#AA00FF,fill:#E1BEE7
style subGraph1 stroke:#AA00FF,fill:#E1BEE7
style subGraph2 stroke:#2962FF,fill:#BBDEFB