共用体

深入理解共用体

共用体是C语言中一种特殊的构造类型,它允许不同类型的数据共享同一内存空间。东巴文(db-w.cn) 将带你深入理解共用体的原理与实践。

💡 东巴文观点:共用体是C语言节省内存的利器,掌握共用体能够让你编写更高效的程序。

什么是共用体

共用体的定义

#include <stdio.h>

void unionDefinition() {
    printf("=== 东巴文共用体的定义 ===\n\n");
    
    printf("共用体(Union):\n");
    printf("  一种特殊的构造类型\n");
    printf("  所有成员共享同一内存空间\n");
    printf("  同一时刻只能使用一个成员\n\n");
    
    printf("共用体的特点:\n");
    printf("  1. 所有成员共享同一内存空间\n");
    printf("  2. 大小等于最大成员的大小\n");
    printf("  3. 同一时刻只能使用一个成员\n");
    printf("  4. 修改一个成员会影响其他成员\n");
    printf("  5. 节省内存空间\n");
}

int main() {
    unionDefinition();
    return 0;
}

共用体的声明

#include <stdio.h>
#include <string.h>

// 方式1:先定义共用体类型,再声明变量
union Data1 {
    int i;
    float f;
    char str[20];
};

// 方式2:定义共用体类型的同时声明变量
union Data2 {
    int i;
    float f;
    char str[20];
} data1, data2;

// 方式3:匿名共用体
union {
    int i;
    float f;
} data3;

// 方式4:使用typedef
typedef union {
    int i;
    float f;
    char str[20];
} Data3;

void unionDeclaration() {
    printf("=== 东巴文共用体的声明 ===\n\n");
    
    union Data1 data;
    Data3 data4;
    
    data.i = 100;
    data4.i = 200;
    
    printf("data.i = %d\n", data.i);
    printf("data4.i = %d\n", data4.i);
}

int main() {
    unionDeclaration();
    return 0;
}

共用体的初始化

初始化方式

#include <stdio.h>
#include <string.h>

typedef union {
    int i;
    float f;
    char str[20];
} Data;

void unionInitialization() {
    printf("=== 东巴文共用体的初始化 ===\n\n");
    
    // 方式1:初始化第一个成员
    Data data1 = {100};
    printf("data1.i = %d\n", data1.i);
    
    // 方式2:指定成员初始化(C99)
    Data data2 = {.f = 95.5};
    printf("data2.f = %.1f\n", data2.f);
    
    // 方式3:指定成员初始化(C99)
    Data data3 = {.str = "东巴文"};
    printf("data3.str = %s\n", data3.str);
}

int main() {
    unionInitialization();
    return 0;
}

共用体成员访问

点运算符

#include <stdio.h>
#include <string.h>

typedef union {
    int i;
    float f;
    char str[20];
} Data;

void dotOperator() {
    printf("=== 东巴文点运算符 ===\n\n");
    
    Data data;
    
    // 使用int成员
    data.i = 100;
    printf("使用int成员:\n");
    printf("  data.i = %d\n", data.i);
    
    // 使用float成员
    data.f = 95.5;
    printf("\n使用float成员:\n");
    printf("  data.f = %.1f\n", data.f);
    printf("  data.i = %d(已被覆盖)\n", data.i);
    
    // 使用char数组成员
    strcpy(data.str, "东巴文");
    printf("\n使用char数组成员:\n");
    printf("  data.str = %s\n", data.str);
    printf("  data.i = %d(已被覆盖)\n", data.i);
    printf("  data.f = %.1f(已被覆盖)\n", data.f);
}

int main() {
    dotOperator();
    return 0;
}

箭头运算符

#include <stdio.h>
#include <string.h>

typedef union {
    int i;
    float f;
    char str[20];
} Data;

void arrowOperator() {
    printf("=== 东巴文箭头运算符 ===\n\n");
    
    Data data;
    Data *ptr = &data;
    
    // 使用箭头运算符访问成员
    ptr->i = 100;
    printf("使用箭头运算符访问:\n");
    printf("  ptr->i = %d\n", ptr->i);
    
    ptr->f = 95.5;
    printf("\n  ptr->f = %.1f\n", ptr->f);
    printf("  ptr->i = %d(已被覆盖)\n", ptr->i);
}

int main() {
    arrowOperator();
    return 0;
}

共用体的大小

大小计算

#include <stdio.h>

typedef union {
    char c;
    int i;
    double d;
} Data1;

typedef union {
    int i;
    double d;
} Data2;

void unionSize() {
    printf("=== 东巴文共用体的大小 ===\n\n");
    
    printf("Data1大小:%zu字节\n", sizeof(Data1));
    printf("  char大小:%zu字节\n", sizeof(char));
    printf("  int大小:%zu字节\n", sizeof(int));
    printf("  double大小:%zu字节\n", sizeof(double));
    
    printf("\nData2大小:%zu字节\n", sizeof(Data2));
    printf("  int大小:%zu字节\n", sizeof(int));
    printf("  double大小:%zu字节\n", sizeof(double));
    
    printf("\n共用体大小规则:\n");
    printf("  1. 大小等于最大成员的大小\n");
    printf("  2. 可能需要考虑内存对齐\n");
    printf("  3. 所有成员共享同一内存空间\n");
}

int main() {
    unionSize();
    return 0;
}

共用体与结构体的区别

对比示例

#include <stdio.h>

typedef struct {
    int i;
    float f;
    char c;
} StructData;

typedef union {
    int i;
    float f;
    char c;
} UnionData;

void structVsUnion() {
    printf("=== 东巴文共用体与结构体的区别 ===\n\n");
    
    printf("结构体:\n");
    printf("  大小:%zu字节\n", sizeof(StructData));
    printf("  成员独立存储\n");
    printf("  可以同时使用所有成员\n");
    printf("  修改一个成员不影响其他成员\n\n");
    
    printf("共用体:\n");
    printf("  大小:%zu字节\n", sizeof(UnionData));
    printf("  成员共享内存\n");
    printf("  同一时刻只能使用一个成员\n");
    printf("  修改一个成员会影响其他成员\n");
}

int main() {
    structVsUnion();
    return 0;
}

东巴文对比表

特性 结构体 共用体
成员存储 独立存储 共享存储
大小 所有成员大小之和 最大成员的大小
同时使用 可以同时使用所有成员 同一时刻只能使用一个成员
修改影响 修改一个成员不影响其他成员 修改一个成员会影响其他成员
内存效率 较低 较高
适用场景 需要同时存储多个成员 互斥数据,节省内存

共用体的应用

1. 节省内存

#include <stdio.h>

typedef struct {
    int type;  // 0: int, 1: float, 2: char
    union {
        int intValue;
        float floatValue;
        char charValue;
    } value;
} Variant;

void saveMemory() {
    printf("=== 东巴文节省内存 ===\n\n");
    
    Variant variants[3];
    
    // 存储int
    variants[0].type = 0;
    variants[0].value.intValue = 100;
    
    // 存储float
    variants[1].type = 1;
    variants[1].value.floatValue = 95.5;
    
    // 存储char
    variants[2].type = 2;
    variants[2].value.charValue = 'A';
    
    printf("变体数据:\n");
    for (int i = 0; i < 3; i++) {
        printf("变体%d: ", i + 1);
        switch (variants[i].type) {
            case 0:
                printf("int = %d\n", variants[i].value.intValue);
                break;
            case 1:
                printf("float = %.1f\n", variants[i].value.floatValue);
                break;
            case 2:
                printf("char = %c\n", variants[i].value.charValue);
                break;
        }
    }
    
    printf("\n节省内存:\n");
    printf("  使用共用体:%zu字节\n", sizeof(Variant));
    printf("  不使用共用体:%zu字节\n", sizeof(int) + sizeof(float) + sizeof(char));
}

int main() {
    saveMemory();
    return 0;
}

2. 数据类型转换

#include <stdio.h>

typedef union {
    int i;
    float f;
} IntFloat;

void dataTypeConversion() {
    printf("=== 东巴文数据类型转换 ===\n\n");
    
    IntFloat converter;
    
    // int转float
    converter.i = 100;
    printf("int值:%d\n", converter.i);
    printf("对应的float值:%f\n", converter.f);
    
    // float转int
    converter.f = 95.5;
    printf("\nfloat值:%.1f\n", converter.f);
    printf("对应的int值:%d\n", converter.i);
    
    printf("\n注意:\n");
    printf("  这不是类型转换,而是同一内存的不同解释\n");
    printf("  可以用于查看浮点数的内部表示\n");
}

int main() {
    dataTypeConversion();
    return 0;
}

3. 网络数据包

#include <stdio.h>
#include <string.h>

typedef union {
    struct {
        unsigned char byte1;
        unsigned char byte2;
        unsigned char byte3;
        unsigned char byte4;
    } bytes;
    unsigned int value;
} IPAddress;

void networkPacket() {
    printf("=== 东巴文网络数据包 ===\n\n");
    
    IPAddress ip;
    
    // 方式1:按字节设置
    ip.bytes.byte1 = 192;
    ip.bytes.byte2 = 168;
    ip.bytes.byte3 = 1;
    ip.bytes.byte4 = 1;
    
    printf("IP地址(按字节):\n");
    printf("  %d.%d.%d.%d\n", 
           ip.bytes.byte1, ip.bytes.byte2, 
           ip.bytes.byte3, ip.bytes.byte4);
    printf("  整数值:%u\n", ip.value);
    
    // 方式2:按整数设置
    ip.value = 3232235777;  // 192.168.1.1
    
    printf("\nIP地址(按整数):\n");
    printf("  整数值:%u\n", ip.value);
    printf("  %d.%d.%d.%d\n", 
           ip.bytes.byte1, ip.bytes.byte2, 
           ip.bytes.byte3, ip.bytes.byte4);
}

int main() {
    networkPacket();
    return 0;
}

4. 硬件寄存器

#include <stdio.h>

typedef union {
    struct {
        unsigned char bit0 : 1;
        unsigned char bit1 : 1;
        unsigned char bit2 : 1;
        unsigned char bit3 : 1;
        unsigned char bit4 : 1;
        unsigned char bit5 : 1;
        unsigned char bit6 : 1;
        unsigned char bit7 : 1;
    } bits;
    unsigned char value;
} Register;

void hardwareRegister() {
    printf("=== 东巴文硬件寄存器 ===\n\n");
    
    Register reg;
    
    // 按位设置
    reg.bits.bit0 = 1;
    reg.bits.bit3 = 1;
    reg.bits.bit7 = 1;
    
    printf("按位设置:\n");
    printf("  bit0 = %d\n", reg.bits.bit0);
    printf("  bit3 = %d\n", reg.bits.bit3);
    printf("  bit7 = %d\n", reg.bits.bit7);
    printf("  整数值 = %d\n", reg.value);
    
    // 按字节设置
    reg.value = 0xAA;
    
    printf("\n按字节设置(0xAA):\n");
    printf("  bit0 = %d\n", reg.bits.bit0);
    printf("  bit1 = %d\n", reg.bits.bit1);
    printf("  bit2 = %d\n", reg.bits.bit2);
    printf("  bit3 = %d\n", reg.bits.bit3);
    printf("  bit4 = %d\n", reg.bits.bit4);
    printf("  bit5 = %d\n", reg.bits.bit5);
    printf("  bit6 = %d\n", reg.bits.bit6);
    printf("  bit7 = %d\n", reg.bits.bit7);
}

int main() {
    hardwareRegister();
    return 0;
}

共用体数组

共用体数组的定义

#include <stdio.h>

typedef union {
    int i;
    float f;
    char c;
} Data;

void unionArray() {
    printf("=== 东巴文共用体数组 ===\n\n");
    
    Data dataArray[3];
    
    dataArray[0].i = 100;
    dataArray[1].f = 95.5;
    dataArray[2].c = 'A';
    
    printf("共用体数组:\n");
    printf("  dataArray[0].i = %d\n", dataArray[0].i);
    printf("  dataArray[1].f = %.1f\n", dataArray[1].f);
    printf("  dataArray[2].c = %c\n", dataArray[2].c);
}

int main() {
    unionArray();
    return 0;
}

共用体指针

共用体指针的定义

#include <stdio.h>

typedef union {
    int i;
    float f;
    char c;
} Data;

void unionPointer() {
    printf("=== 东巴文共用体指针 ===\n\n");
    
    Data data;
    Data *ptr = &data;
    
    ptr->i = 100;
    printf("使用指针访问:\n");
    printf("  ptr->i = %d\n", ptr->i);
    
    ptr->f = 95.5;
    printf("  ptr->f = %.1f\n", ptr->f);
    printf("  ptr->i = %d(已被覆盖)\n", ptr->i);
}

int main() {
    unionPointer();
    return 0;
}

东巴文最佳实践

1. 使用类型标识

#include <stdio.h>

typedef struct {
    int type;  // 类型标识
    union {
        int intValue;
        float floatValue;
        char charValue;
    } value;
} TaggedUnion;

void useTypeTag() {
    printf("=== 东巴文使用类型标识 ===\n\n");
    
    TaggedUnion data;
    
    data.type = 0;  // 0表示int
    data.value.intValue = 100;
    
    printf("使用类型标识:\n");
    printf("  类型:%d\n", data.type);
    printf("  值:%d\n", data.value.intValue);
    
    printf("\n类型标识的作用:\n");
    printf("  1. 记录当前使用的成员类型\n");
    printf("  2. 避免错误访问\n");
    printf("  3. 提高代码安全性\n");
}

int main() {
    useTypeTag();
    return 0;
}

2. 避免错误访问

#include <stdio.h>

typedef union {
    int i;
    float f;
} Data;

void avoidWrongAccess() {
    printf("=== 东巴文避免错误访问 ===\n\n");
    
    Data data;
    data.i = 100;
    
    printf("正确访问:\n");
    printf("  data.i = %d\n", data.i);
    
    printf("\n错误访问:\n");
    printf("  data.f = %f(无意义的值)\n", data.f);
    
    printf("\n避免错误访问:\n");
    printf("  1. 使用类型标识\n");
    printf("  2. 记住当前使用的成员\n");
    printf("  3. 避免访问未初始化的成员\n");
}

int main() {
    avoidWrongAccess();
    return 0;
}

3. 使用typedef简化类型

#include <stdio.h>

typedef union {
    int i;
    float f;
    char c;
} Data;

void useTypedef() {
    printf("=== 东巴文使用typedef简化类型 ===\n\n");
    
    Data data;
    data.i = 100;
    
    printf("typedef优势:\n");
    printf("  1. 简化类型声明\n");
    printf("  2. 提高可读性\n");
    printf("  3. 便于移植\n");
    printf("  4. 隐藏实现细节\n");
    
    printf("\ndata.i = %d\n", data.i);
}

int main() {
    useTypedef();
    return 0;
}

东巴文验证清单

完成本章学习后,请确认:

  • 理解共用体的定义
  • 掌握共用体的声明
  • 掌握共用体的初始化
  • 掌握共用体成员访问
  • 理解共用体的大小
  • 理解共用体与结构体的区别
  • 掌握共用体的应用
  • 掌握共用体数组
  • 掌握共用体指针
  • 掌握最佳实践

下一步学习

掌握共用体后,你可以继续学习:

如果遇到问题,欢迎访问 东巴文(db-w.cn) 获取帮助!


东巴文(db-w.cn) - 让编程学习更简单

🎯 东巴文共用体提示:共用体是C语言节省内存的利器。在 db-w.cn,我们会通过大量实例帮你掌握共用体!