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

C语言使用fread读取二进制文件结构体位域字段解析问题

问题核心原因

  • 位域不能单独执行fread读取:C语言中的位域是按比特位共享底层存储单元的,你定义的4个1位宽的位域总共仅占用4比特空间,打包在同一个字节中,单独对位域成员取地址、调用sizeof、执行fread都是不符合规范的操作,会导致文件读取偏移完全错位。
  • 打印格式符错误:原printf语句中四个位域对应的位置写了无效的%占位符,没有指定输出格式。
  • 结构体默认填充对齐:编译器默认会在结构体成员之间插入空白填充字节,来优化内存访问效率,会导致你按单个成员大小依次读取的内容和实际内存布局不匹配,字段值全部错乱。

修复方案

第一步:修改结构体为紧凑无填充布局,调整位域定义

使用编译器指令关闭结构体填充,同时将位域的底层存储类型改为unsigned char,适配4比特的存储需求:

#define MAX_HAT 9
#include<stdio.h>
#include<stdlib.h>

// 按1字节对齐,关闭结构体填充
#pragma pack(1)
struct test
{
    short int land;
    float experience;
    char boys;
    short int angle;
    double industry;
    int thread;
    long int shoe;
    float kitty;
    unsigned char price;
    
    // 4个1位宽位域,共占4比特,和你提到的0xd(二进制1101)对应
    unsigned char father: 1;
    unsigned char room: 1;
    unsigned char attraction: 1;
    unsigned char cake: 1;
    // 如果文件中该字节剩余4位无意义,可以加reserved占坑:unsigned char reserved:4;
    
    int foot;
    char hat[MAX_HAT];
    char nest;
    float bean;
};
// 恢复编译器默认对齐规则
#pragma pack()

第二步:修改读取逻辑,一次性读入整个结构体

不用单独读取每个成员,直接读整个结构体即可,避免偏移错误:

int main(int argc, char **argv)
{
    struct test t1;
    
    FILE *fp;
    if (argc < 2) {
        fprintf(stderr, "Usage: %s input_file\n", argv[0]);
        exit(1);
    }
    
    fp = fopen(argv[1], "rb");
    if (fp == NULL){
        fprintf(stderr, "Cannot open the file %s\n", argv[1]);
        exit(1);
    }

    printf("land, experience, boys, angle, industry, thread, shoe, kitty, price, father, room, attraction, cake, foot, hat, nest, bean \n");

    // 一次性读入整个结构体,替代之前的多次fread
    while(fread(&t1, sizeof(struct test), 1, fp) == 1)
    {
        // 四个位域用%u输出即可,只会显示0或1
        printf("%d, %f, %i, %i, %f, %d, %ld, %f, %u, %u, %u, %u, %u, %x, %s, %c, %f\n", 
        t1.land, t1.experience, t1.boys, t1.angle, t1.industry, t1.thread, 
        t1.shoe, t1.kitty, t1.price, t1.father, t1.room, t1.attraction, t1.cake,
        t1.foot, t1.hat, t1.nest, t1.bean);
    }

    fclose(fp);
    return 0;
}

第三步:调整位域顺序适配文件比特布局

如果读出来的四个位域值顺序和预期的1、1、0、1不符,调整结构体中四个位域的定义顺序即可,因为C标准没有规定位域在字节中的排列顺序,会根据编译器、大小端环境变化,反过来定义就能适配你文件中的比特顺序。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 14:45:01