C语言自定义类型:联合体与枚举详解

C语言自定义类型:联合体与枚举

1. 联合体

联合体的所有成员共享同一段内存:

1
2
3
4
5
6
union Data
{
int integer;
float real;
unsigned char bytes[4];
};

同一时刻通常只有最后写入的成员具有有效意义。

1
2
3
union Data data;
data.integer = 42;
printf("%d\n", data.integer);

2. 联合体大小

联合体大小至少能容纳最大成员,并满足最严格成员的对齐要求,最终大小可能向对齐数整数倍上取整。

1
2
3
4
5
union Example
{
char chars[5];
int value;
};

在 int 按4字节对齐的平台上,其大小常为8,而不是简单的5。具体结果应使用 sizeof 验证。

3. 带标签的联合体

为了记录当前哪个成员有效,常把枚举与联合体组合:

1
2
3
4
5
6
7
8
9
10
11
12
enum ValueType { VALUE_INT, VALUE_DOUBLE, VALUE_TEXT };

struct Value
{
enum ValueType type;
union
{
int integer;
double real;
const char *text;
} data;
};

读取前先检查 type,这类设计称为带标签联合体。

4. 枚举

枚举为一组相关整数常量提供有意义的名字:

1
2
3
4
5
6
7
8
9
10
enum Weekday
{
MONDAY = 1,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
};

未显式赋值的枚举项在前一项基础上加1。

1
2
3
4
5
6
7
8
9
10
11
enum State { STATE_IDLE, STATE_RUNNING, STATE_STOPPED };

void handle_state(enum State state)
{
switch (state)
{
case STATE_IDLE: break;
case STATE_RUNNING: break;
case STATE_STOPPED: break;
}
}

5. 枚举的优点

  • 比数字常量更易读;
  • 相关取值集中管理;
  • 便于 switch 表达有限状态;
  • 调试器可以显示枚举名称;
  • 避免大量含义不明的“魔法数字”。

枚举并不会在所有C编译器中提供严格类型安全,仍需校验来自文件、网络或用户输入的整数值。

6. 应用场景

联合体适合节省互斥数据的存储空间、实现不同载荷消息;枚举适合状态、选项、错误码和命令类型。二者组合常用于协议解析器、抽象语法树和状态机。

7. 总结

结构体的成员各自占空间,联合体成员共享空间,枚举则为有限整数集合命名。联合体最关键的安全规则是:程序必须知道当前哪个成员有效。