C 共用体

C语言共用体知识详解

C语言共用体(union)知识详解

专为编程小白准备的通俗易懂的共用体知识总结

什么是共用体?

共用体(union)是C语言中一种特殊的数据类型,它允许在相同的内存位置存储不同的数据类型。

核心特点:

  • 所有成员共享同一块内存空间
  • 任何时候只能有一个成员包含有效值
  • 内存大小由最大成员决定
  • 节省内存空间,但需要小心使用

定义方式:

union 共用体名称 {
  数据类型 成员1;
  数据类型 成员2;
  // 更多成员…
} 变量名;

共用体与结构体的区别

结构体(struct)

  • 每个成员都有自己的内存空间
  • 所有成员可以同时存储值
  • 内存大小 = 所有成员大小之和 + 内存对齐调整
  • 适合存储多个相关数据项

共用体(union)

  • 所有成员共享同一内存空间
  • 一次只能使用一个成员
  • 内存大小 = 最大成员的大小
  • 适合节省内存或多种类型数据复用

内存对比示例:

struct MyStruct {
  int a; // 4字节
  float b; // 4字节
  char c; // 1字节
}; // 总大小 ≈ 12字节 (考虑内存对齐)

union MyUnion {
  int a; // 4字节
  float b; // 4字节
  char c; // 1字节
}; // 总大小 = 4字节 (最大成员的大小)

共用体使用场景

1. 节省内存空间

当多个数据不会同时使用时,共用体可以大幅节省内存。

2. 实现多类型变量

需要存储不同类型数据但一次只用一种类型时。

3. 硬件寄存器访问

在嵌入式编程中,同一内存位置可能对应不同功能的寄存器。

4. 协议解析

解析网络数据包时,同一字段可能有不同的解释方式。

5. 类型转换技巧

在不进行强制类型转换的情况下查看变量在不同类型下的表示。

// 示例:使用共用体提取浮点数的字节表示
union FloatExtractor {
  float f_value;
  unsigned char bytes[4];
};

union FloatExtractor fe;
fe.f_value = 3.14159f;
printf(“浮点数的字节表示: “);
for(int i = 0; i < 4; i++) {
  printf(“%02X “, fe.bytes[i]);
}

内存布局可视化

结构体(struct)内存布局

int成员 (4字节)

0x0000 – 0x0003

float成员 (4字节)

0x0004 – 0x0007

char成员 (1字节)

0x0008

结构体总大小: 12字节 (考虑对齐)

共用体(union)内存布局

int成员 (4字节)

所有成员共享
同一内存区域

float成员 (4字节)

所有成员共享
同一内存区域

char成员 (1字节)

所有成员共享
同一内存区域

共用体总大小: 4字节 (最大成员的大小)

使用注意事项

1. 成员覆盖问题

给一个成员赋值会覆盖其他成员的值,因为所有成员共享同一内存。

2. 类型安全

C语言不会检查你访问的是哪个成员,需要程序员自己记录当前使用的是哪个成员。

3. 初始化

只能初始化共用体的第一个成员。

4. 大小端问题

在不同系统中,字节顺序可能不同,会影响共用体中多字节数据的解释。

// 错误使用示例:访问被覆盖的成员
union Data {
  int i;
  float f;
};

union Data data;
data.i = 10; // 设置整数值
printf(“%d”, data.i); // 正确:输出10

data.f = 3.14; // 设置浮点值
printf(“%d”, data.i); // 错误!i的值已被覆盖

完整示例代码

#include <stdio.h>
#include <string.h>
// 定义一个共用体
union Data {
  int i;
  float f;
  char str[20];
};

int main() {
  union Data data;

  printf(“共用体大小: %ld 字节\n\n”, sizeof(data));

  // 使用整形成员
  data.i = 42;
  printf(“data.i 设置: %d\n”, data.i);
  printf(“尝试访问 data.f: %f (无意义)\n\n”, data.f);

  // 使用浮点成员 – 覆盖之前的整数
  data.f = 3.14159;
  printf(“data.f 设置: %f\n”, data.f);
  printf(“尝试访问 data.i: %d (无意义)\n\n”, data.i);

  // 使用字符串成员 – 覆盖之前的浮点数
  strcpy(data.str, “Hello, Union!”);
  printf(“data.str 设置: %s\n”, data.str);
  printf(“尝试访问 data.f: %f (无意义)\n\n”, data.f);

  // 正确用法:使用标签记录当前存储的类型
  struct TaggedData {
    int type; // 0=int, 1=float, 2=string
    union {
      int i;
      float f;
      char str[20];
    } data;
  };

  struct TaggedData tagged;
  tagged.type = 0; // 存储整数
  tagged.data.i = 100;

  // 使用时检查类型
  if(tagged.type == 0) {
    printf(“\n带标签的共用体: int值 = %d\n”, tagged.data.i);
  }

  return 0;
}

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部