C语言中union(共同体)的特点
1. 内存共享特性
cs
union Data {
int i;
float f;
char str[20];
}; // 所有成员共享同一块内存空间
-
所有成员共享同一段内存
-
大小为最大成员的大小
-
同一时间只能存储一个成员的值
2. 典型特点
-
内存覆盖:修改一个成员会影响其他成员
-
节省内存:相比struct更节省空间
-
类型转换:可实现不同类型数据的便捷转换
-
大小端检测:可用于检测系统字节序
3. 示例演示
cs
union Example {
uint32_t word;
uint8_t bytes[4];
struct {
uint8_t b0, b1, b2, b3;
};
};
// 使用示例
union Example data;
data.word = 0x12345678;
printf("Byte0: 0x%02X\n", data.bytes[0]); // 输出取决于字节序
STM32中union的典型应用
1. 寄存器位域操作
cs
// GPIO寄存器位域访问
typedef union {
struct {
uint32_t MODER0 : 2; // 模式设置
uint32_t MODER1 : 2;
uint32_t OTYPER0 : 1; // 输出类型
uint32_t OTYPER1 : 1;
uint32_t OSPEEDR0 : 2; // 输出速度
// ... 其他位域
} bits;
uint32_t reg; // 整个32位寄存器
} GPIO_TypeDef;
// 使用示例
GPIO_TypeDef GPIOA;
GPIOA.bits.MODER0 = 0x01; // 设置位域
uint32_t reg_val = GPIOA.reg; // 获取完整寄存器值
2. 数据包解析
cs
// CAN报文数据结构
typedef union {
struct {
uint32_t id : 29; // 标准ID
uint32_t rtr : 1; // 远程帧标志
uint32_t ide : 1; // IDE标志
uint32_t dlc : 4; // 数据长度
uint8_t data[8]; // 数据域
} frame;
uint8_t raw[13]; // 原始字节数组
} CAN_Packet_t;
// 网络协议解析
typedef union {
struct {
uint16_t source_port;
uint16_t dest_port;
uint16_t length;
uint16_t checksum;
} header;
uint8_t bytes[8];
} UDP_Header_t;
3. 浮点数与字节数组转换
cs
// 传感器数据处理
union FloatConverter {
float value;
uint8_t bytes[4];
};
// 使用示例
union FloatConverter sensor_data;
// 从UART接收4字节数据
uart_receive(sensor_data.bytes, 4);
float temperature = sensor_data.value; // 转换为浮点数
4. 多数据类型访问
cs
// ADC数据访问
union ADC_Data {
uint16_t raw_value; // 原始ADC值
struct {
uint8_t low_byte;
uint8_t high_byte;
} bytes;
float voltage; // 转换后的电压值
};
// 使用示例
union ADC_Data adc_result;
adc_result.raw_value = ADC1->DR; // 读取ADC寄存器
uart_send(adc_result.bytes.low_byte); // 发送低字节
float vol = adc_result.raw_value * 3.3 / 4095; // 计算电压
5. 状态标志位管理
cs
// 系统状态标志
union System_Status {
struct {
uint8_t sensor_ready : 1;
uint8_t comm_ok : 1;
uint8_t battery_low : 1;
uint8_t fault_flag : 1;
uint8_t reserved : 4;
} flags;
uint8_t status_byte;
};
// 使用示例
union System_Status sys_status;
sys_status.flags.sensor_ready = 1;
if (sys_status.flags.fault_flag) {
// 处理故障
}
6. 通信协议处理
cs
// Modbus RTU协议
typedef union {
struct {
uint8_t address;
uint8_t function_code;
uint16_t register_addr;
uint16_t data;
uint16_t crc;
} fields;
uint8_t raw_frame[8];
} Modbus_Frame_t;
// 使用示例
Modbus_Frame_t frame;
uart_receive(frame.raw_frame, 8);
if (frame.fields.address == 0x01) {
// 处理地址为1的设备
}
使用注意事项
优点:
-
节省内存:特别适合内存受限的嵌入式系统
-
高效访问:可直接访问数据的各个部分
-
类型安全:提供结构化的数据访问方式
风险:
-
数据覆盖:不当使用会导致数据被意外覆盖
-
字节序问题:跨平台时需要注意大小端
-
可读性:过度使用可能降低代码可读性
最佳实践:
cs
// 推荐做法:添加清晰的注释和类型定义
typedef union {
struct {
uint32_t mantissa : 23;
uint32_t exponent : 8;
uint32_t sign : 1;
} ieee754;
float fval;
} IEEE754_Float __attribute__((packed)); // 确保紧凑存储
在STM32嵌入式开发中,union常用于:
-
寄存器配置:位域操作
-
通信协议:数据包解析
-
数据转换:不同格式间的转换
-
状态管理:标志位操作
-
内存优化:节省有限的RAM资源