Linux环境下的C语言编程(二十二)
前言
本文作为一个学习C语言学习笔记,记录 【史上最强最细腻的linux嵌入式C语言学习教程【李慧芹老师】-哔哩x课程笔记和自己的困惑之处。请各位大佬指出我的不足之处,更好的促进我的成长。
共用体详解
共用体(Union)是C语言中一种特殊的数据结构,它允许在相同的内存位置存储不同的数据类型。
定义
共用体的定义语法与结构体类似:
union [共用体标签] {成员定义;成员定义;...成员定义;
} [一个或多个共用体变量];
示例:
union Data {int i;float f;char str[20];
} data;
内存分配特性
-
共用体的大小等于其最大成员的大小
-
所有成员共享同一块内存空间
-
任何时候只能有一个成员包含有效值
#include <stdio.h>union Data {int i;float f;char str[20];
};int main() {union Data data;printf("共用体大小: %zu 字节\n", sizeof(data)); // 输出: 20return 0;
}
共用体的使用
基本用法示例
#include <stdio.h>
#include <string.h>union Data {int i;float f;char str[20];
};int main() {union Data data;// 正确用法:同一时间只使用一个成员data.i = 10;printf("data.i = %d\n", data.i);data.f = 3.14;printf("data.f = %.2f\n", data.f);strcpy(data.str, "Hello");printf("data.str = %s\n", data.str);return 0;
}
错误用法示例
#include <stdio.h>
#include <string.h>union Data {int i;float f;char str[20];
};int main() {union Data data;// 错误用法:连续赋值会破坏之前的值data.i = 10;data.f = 3.14;strcpy(data.str, "Hello");// 此时只有最后一个赋值是有效的printf("data.i = %d (已损坏)\n", data.i);printf("data.f = %f (已损坏)\n", data.f);printf("data.str = %s (正确)\n", data.str);return 0;
}
共用体的实际应用场景
1. 节省内存空间
#include <stdio.h>// 用于存储不同类型数据的配置项
union ConfigValue {int int_val;float float_val;char string_val[32];
};struct ConfigItem {char name[32];int type; // 0: int, 1: float, 2: stringunion ConfigValue value;
};int main() {struct ConfigItem config;strcpy(config.name, "timeout");config.type = 0;config.value.int_val = 30;printf("配置项: %s = ", config.name);switch(config.type) {case 0: printf("%d\n", config.value.int_val); break;case 1: printf("%f\n", config.value.float_val); break;case 2: printf("%s\n", config.value.string_val); break;}return 0;
}
2. 类型转换
#include <stdio.h>union Converter {int i;float f;unsigned char bytes[4];
};int main() {union Converter conv;// 查看浮点数的二进制表示conv.f = 3.14;printf("浮点数 %.2f 的二进制表示: ", conv.f);for(int i = 0; i < 4; i++) {printf("%02X ", conv.bytes[i]);}printf("\n");// 整数和浮点数的内存共享conv.i = 123456;printf("整数 %d 对应的浮点数: %f\n", conv.i, conv.f);return 0;
}
3. 协议数据处理
#include <stdio.h>// 网络协议数据包
union NetworkPacket {struct {unsigned char type;unsigned char flags;unsigned short length;} header;unsigned char raw_data[1024];
};int main() {union NetworkPacket packet;// 以原始字节形式接收数据// 模拟接收数据packet.raw_data[0] = 0x01; // typepacket.raw_data[1] = 0x80; // flagspacket.raw_data[2] = 0x00; // length high bytepacket.raw_data[3] = 0x40; // length low byte (64)// 通过结构体访问解析后的数据printf("数据包类型: 0x%02X\n", packet.header.type);printf("数据包标志: 0x%02X\n", packet.header.flags);printf("数据包长度: %d\n", packet.header.length);return 0;
}
共用体与结构体的比较
| 特性 | 共用体(Union) | 结构体(Struct) |
|---|---|---|
| 内存使用 | 共享内存 | 独立内存 |
| 大小 | 等于最大成员大小 | 等于所有成员大小之和(考虑对齐) |
| 数据存储 | 同一时间只能存储一个成员的值 | 可以同时存储所有成员的值 |
| 用途 | 节省内存,类型转换 | 组织相关数据 |
共用体嵌套
#include <stdio.h>// 嵌套共用体示例
union Variant {int int_val;float float_val;struct {int type;union {int i;float f;char *str;} value;} tagged;
};int main() {union Variant var;// 使用简单形式var.int_val = 100;printf("简单形式: %d\n", var.int_val);// 使用带标签的形式var.tagged.type = 1; // 1 表示浮点数var.tagged.value.f = 3.14;printf("带标签形式: 类型=%d, 值=%.2f\n", var.tagged.type, var.tagged.value.f);return 0;
}
注意事项
-
内存覆盖问题:共用体成员共享内存,修改一个成员会影响其他成员
-
类型安全:需要程序员自己跟踪当前有效的成员类型
-
初始化:只能初始化第一个成员
-
赋值:最后一次赋值决定了当前有效的成员
// 正确的初始化方式
union Data data = {10}; // 只能初始化第一个成员// 错误的方式
// union Data data = {10, 3.14, "hello"}; // 编译错误
共用体是C语言中一个强大的特性,合理使用可以节省内存并实现灵活的数据处理,但需要谨慎使用以避免数据损坏。
