1.基本概念
在 C 语言中,联合(Union)是一种特殊的数据类型,它允许在同一段内存空间中存储不同类型的数据。联合成员共享内存空间,联合的大小取决于其成员中最大的类型的大小。当定义一个联合时,系统会为联合分配足够的内存来容纳其中最大的成员。
例如:定义一个unsigned int和unsigned char的联合类型,其语法如下:
union IntCharUnion {
unsigned int int_value;
unsigned char char_array[sizeof(unsigned int)];
};
在这个联合定义中:
1. union是关键字,用于声明一个联合类型。
2. IntCharUnion是联合类型的名称,可以根据需要进行修改。
3. 联合中有两个成员:
- int_value是unsigned int类型的成员,用于存储一个无符号整数。
- char_array是一个unsigned char类型的数组,其大小设置为sizeof(unsigned int),这意味着这个数组的大小刚好可以容纳一个unsigned int类型的数据。这样就可以通过这个数组来访问unsigned int数据的每个字节。
2.编程实例
include <stdio.h>
#include <string.h>
union IntCharUnion {
unsigned int int_value;
unsigned char char_array[sizeof(unsigned int)];
};
int main() {
union IntCharUnion my_union;
my_union.int_value = 0x12345678;
// 以字节为单位打印unsigned int的值
for (int i = 0; i < sizeof(unsigned int); i++) {
printf("%02x ", my_union.char_array[i]);
}
printf("\n");
// 修改字节数组的值
my_union.char_array[0] = 0x77;
my_union.char_array[1] = 0x66;
my_union.char_array[2] = 0x55;
my_union.char_array[3] = 0x44;
// 打印修改后的unsigned int的值
printf("%08x\n", my_union.int_value);
return 0;
}
3.一个经典的使用场景
假设程序A要发送一个unsigned int型数据给程序B,但是在链路层数据都是按字节(unsigned char)来发送的,那么使用联合类型就可以方便的完成unsigned int到unsigned char的转换。
程序A:
//代码片段
union IntCharUnion dataLen;
dataLen.int_value = 12345678;
//假设发送函数send原型是void send(unsigned char *data,int len);
//使用方法如下
send(dataLen.char_array,4);
...
程序B:
//代码片段
union IntCharUnion dataLen;
//假设接收函数recv原型是void recv(unsigned char *data,int len);
//使用方法如下
recv(dataLen.char_array,4);
printf("dataLen = %d\n",dataLen.int_value); //结果是12345678
...
4.扩展
联合类型支持各种各样的组合方式,在实际编程中可以灵活应用。
1.整数和浮点数联合
#include <stdio.h>
union IntFloatUnion {
int int_value;
float float_value;
};
int main() {
union IntFloatUnion my_union;
my_union.int_value = 12345;
printf("The integer value is: %d\n", my_union.int_value);
my_union.float_value = 3.14f;
printf("The floating - point value is: %f\n", my_union.float_value);
return 0;
}
2.结构体和整数联合
#include <stdio.h>
#include <string.h>
struct MyData {
char name[20];
int age;
};
union StructIntUnion {
int int_value;
struct MyData my_data;
};
int main() {
union StructIntUnion my_union;
strcpy(my_union.my_data.name, "John");
my_union.my_data.age = 30;
printf("Name: %s, Age: %d\n", my_union.my_data.name, my_union.my_data.age);
my_union.int_value = 0;
printf("The integer value is: %d\n", my_union.int_value);
return 0;
}
3.int、float和char数组的联合
#include <stdio.h>
#include <string.h>
union IntFloatCharArrayUnion {
int int_value;
float float_value;
char char_array[sizeof(int)]; // 这里假设 int 和 float 大小相同,若不同可按需调整
};
int main() {
union IntFloatCharArrayUnion my_union;
// 使用 int 成员
my_union.int_value = 100;
printf("Integer value: %d\n", my_union.int_value);
// 使用 float 成员
my_union.float_value = 3.14f;
printf("Float value: %f\n", my_union.float_value);
// 使用 char 数组成员
strcpy(my_union.char_array, "Hi!");
printf("Char array value: %s\n", my_union.char_array);
return 0;
}
需要注意的是,由于联合成员共享内存空间,在使用时要确保对当前存储的数据类型有清晰的认识,避免出现数据不一致或错误的情况。例如,在给char_array赋值后,如果直接读取int_value或float_value,其结果将取决于char_array中的字符数据在内存中的二进制表示被解释成整数或浮点数的结果,这通常不是期望的行为,除非是在特定的字节处理或数据转换场景中有意识地这样操作。