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

C语言如何跳过开头uint32_t后读取剩余二进制数据存入结构体

问题分析和解决方案

现有代码的核心错误

  • 文件打开校验逻辑错误:两段代码都先执行读写操作再判断fopen是否返回NULL,如果文件打开失败会直接触发空指针访问崩溃。
  • 跳过开头uint32_t的方法完全错误:fgets是用于读取文本行的接口,遇到换行符/EOF就会终止读取,不适合二进制文件操作;而且uint32_t占4字节,你仅读取2字节,导致后续所有数据的偏移都错位,这是输出数值全错的核心原因。
  • 结构体内存对齐问题:C编译器默认会对结构体成员做内存对齐填充,你的Record结构体中,char[20]之后的float可能会被插入填充字节,直接fread整个结构体会和二进制文件的紧凑布局不匹配,导致读错数据。
  • 第二段代码的专属错误:
    • 读name成员时仅读取1个字节,实际应该读取20个字节的字符串
    • feof用法错误,该标识只有在读取失败后才会置位,会导致循环多执行一次读取到脏数据
    • 未定义Student类型、grade函数,编译直接报错

修正后的实现代码

以下是兼容所有编译器、避免对齐问题的稳定版本:

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

typedef struct Record
{
    char name[20];
    float gpa;
    uint32_t age;
} Record;

int main ()
{
    FILE *in = fopen("input.bin", "rb");
    // 先判断文件是否打开成功
    if (in == NULL) {
        perror("打开文件失败");
        return 3;
    }

    // 跳过开头4字节的uint32_t,两种方式二选一即可
    // 方式1:直接偏移4字节
    fseek(in, sizeof(uint32_t), SEEK_SET);
    // 方式2:需要打印头部数值的话用这个
    // uint32_t header;
    // fread(&header, sizeof(header), 1, in);
    // printf("头部数值:%" PRIu32 "\n", header);

    Record record;
    // 逐个读取成员,避免结构体对齐问题,兼容性更好
    while (fread(record.name, sizeof(record.name), 1, in) == 1
        && fread(&record.gpa, sizeof(record.gpa), 1, in) == 1
        && fread(&record.age, sizeof(record.age), 1, in) == 1) {
        // 确保字符串以\0结尾,避免打印越界
        record.name[sizeof(record.name)-1] = '\0';
        printf("name = %s gpa = %f age: %" PRIu32 "\n", record.name, record.gpa, record.age);
    }

    fclose(in);
    return 0;
}

如果你确认二进制文件的布局和结构体完全匹配,也可以通过编译器指令设置结构体1字节对齐,直接读取整个结构体,GCC/Clang下结构体定义如下:

typedef struct __attribute__((packed)) Record
{
    char name[20];
    float gpa;
    uint32_t age;
} Record;

内容的提问来源于stack exchange,提问作者T. Dawson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 06:15:08