You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C语言中读写二进制文件中的两种不同结构体?

从单个二进制文件读取不同C结构体的可行方案及实现

当然可以!在C语言里实现单个二进制文件存储/读取多种结构体完全没问题,核心是要给每个结构体数据加上“类型标识”,让程序读取时能判断该用哪种结构体去解析字节流。我在做本地数据持久化工具时经常用这种方案,下面给你详细讲实现步骤和注意事项:

核心思路:带类型标记的序列化/反序列化

最通用的做法是在写入每个结构体数据前,先写入一个类型枚举值,告诉后续读取程序“接下来的字节属于哪种结构体”。读取时先读这个标记,再根据标记选择对应的结构体进行数据读取。

步骤1:定义类型枚举和结构体

先定义你要存储的结构体,以及对应的类型标记:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h> // 用固定宽度类型避免字节数问题

// 定义结构体类型标记,用枚举保证可读性
typedef enum {
    TYPE_USER,
    TYPE_PRODUCT,
    TYPE_MAX // 用于边界检查
} StructType;

// 示例结构体1:用户信息
typedef struct {
    uint32_t id;
    char name[32];
    uint8_t age;
} User;

// 示例结构体2:产品信息
typedef struct {
    uint32_t product_id;
    float price;
    uint16_t stock;
} Product;

步骤2:写入二进制文件的实现

写入时,先写类型标记,再写对应的结构体内容:

// 写入单个结构体到文件
int write_struct(FILE *fp, StructType type, const void *data) {
    // 先写入类型标记(用fwrite保证二进制写入)
    if (fwrite(&type, sizeof(StructType), 1, fp) != 1) {
        perror("Failed to write struct type");
        return -1;
    }

    // 根据类型写入对应的结构体数据
    switch(type) {
        case TYPE_USER:
            if (fwrite(data, sizeof(User), 1, fp) != 1) {
                perror("Failed to write User");
                return -1;
            }
            break;
        case TYPE_PRODUCT:
            if (fwrite(data, sizeof(Product), 1, fp) != 1) {
                perror("Failed to write Product");
                return -1;
            }
            break;
        default:
            fprintf(stderr, "Unknown struct type\n");
            return -1;
    }
    return 0;
}

// 示例:写入几个测试数据
int main() {
    FILE *fp = fopen("data.bin", "wb");
    if (!fp) {
        perror("Failed to open file");
        return 1;
    }

    User user1 = {1001, "Alice", 28};
    Product prod1 = {2001, 99.9f, 50};
    User user2 = {1002, "Bob", 32};

    write_struct(fp, TYPE_USER, &user1);
    write_struct(fp, TYPE_PRODUCT, &prod1);
    write_struct(fp, TYPE_USER, &user2);

    fclose(fp);
    return 0;
}

步骤3:读取二进制文件的实现

读取时先读类型标记,再根据标记选择对应结构体解析:

// 读取单个结构体从文件
int read_struct(FILE *fp) {
    StructType type;
    // 先读取类型标记
    if (fread(&type, sizeof(StructType), 1, fp) != 1) {
        // 如果是文件末尾,返回0表示读取完成
        if (feof(fp)) return 0;
        perror("Failed to read struct type");
        return -1;
    }

    // 根据类型读取并解析数据
    switch(type) {
        case TYPE_USER: {
            User user;
            if (fread(&user, sizeof(User), 1, fp) != 1) {
                perror("Failed to read User");
                return -1;
            }
            printf("Read User: ID=%u, Name=%s, Age=%u\n", user.id, user.name, user.age);
            break;
        }
        case TYPE_PRODUCT: {
            Product prod;
            if (fread(&prod, sizeof(Product), 1, fp) != 1) {
                perror("Failed to read Product");
                return -1;
            }
            printf("Read Product: ID=%u, Price=%.1f, Stock=%u\n", prod.product_id, prod.price, prod.stock);
            break;
        }
        default:
            fprintf(stderr, "Unknown struct type in file\n");
            return -1;
    }
    return 1;
}

// 示例:读取整个文件
int main() {
    FILE *fp = fopen("data.bin", "rb");
    if (!fp) {
        perror("Failed to open file");
        return 1;
    }

    int ret;
    // 循环读取直到文件末尾
    while ((ret = read_struct(fp)) == 1);

    if (ret == -1) {
        fclose(fp);
        return 1;
    }

    fclose(fp);
    return 0;
}

必须注意的坑点

  • 结构体内存对齐:不同编译器、不同编译选项下,结构体的内存布局可能不同(比如#pragma pack会改变对齐方式)。如果要跨平台使用,建议手动指定对齐规则,或者把结构体拆成单个字段逐个读写(虽然麻烦但更可靠)。
  • 字节序问题:如果你的程序要跨不同字节序的平台(比如x86是小端,PowerPC是大端),不能直接读写整数、浮点数等类型,需要先转成网络字节序(用htons/htonl等函数),读取时再转回来。
  • 字符串长度:如果结构体里有可变长度字符串,不要直接存char数组,应该先存字符串长度,再存字符串内容,不然读取时不知道该读多少字节。

内容的提问来源于stack exchange,提问作者Sadi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 19:42:39