c - 如何以动态排列的结构加载二进制文件的信息?

标签 c file struct binary fread

我有一个二进制文件,其中包含以下序列:

0-9 char name[10];
10-11 unsigned int n;
12-12+2x4n float coords[n][2];

我需要将其加载到动态结构数组中。

我想将文件中的所有信息保留在类型结构中: 所以我声明了一个这样的结构:

typedef struct{
char name[10]
unsigned int n;
float coords[][2];
}sprites_t;

然后我创建一个函数将其加载到内存中:

    size_t n = 0;
        sprites_t * s = malloc(sizeof(sprites_t)*INITIAL_PACKAGE);
        size_t reads;

       while((reads = fread(s + n,sizeof(sprites_t),INITIAL_PACKAGE,fi)) == INITIAL_PACKAGE ){
            sprites_t * aux = realloc(s,sizeof(sprites_t) * (n+INITIAL_PACKAGE));
            if (aux == NULL) {
                free(s);
                return EXIT_FAILURE;
            }
            s = aux;
            n += INITIAL_PACKAGE;
        }
n += reads;

我无法按照内存中想要的那样制作这个东西。因为在二进制文件中我有一个“unsigned int n”,它是具有坐标矩阵的行数,所以我的结构是灵活的。我怎样才能读到那个N?并在此基础上,使用文件提供的信息完成构建结构。

我真的不知道我的代码是否正确。如果有人有另一种策略来将信息加载到动态结构数组上,欢迎。

最佳答案

如果您的二进制 name 字段正好有 10 个字符长,那么您确实可以将其表示为 char[10],但您应该注意,除非它可靠地终止每个名称(因此实际上只有 9 个可用字符),那么将该数组视为包含 C 字符串是不安全的。如果您希望能够将名称视为字符串,请将数组声明为长一个字符,并使用额外的空间来确保内存中的副本正确终止。

除此之外,您的结构看起来不错,并且您的结构似乎是灵活数组成员的合理用例。但所提供的代码中的其他所有内容都是一场灾难。特别是,

  1. 您不能拥有具有灵活数组成员的对象数组,至少在 FAM 包含任何数据的情况下是如此。即使是动态数组在这里也没有意义,因为元素的大小不一致。链接列表将是更好的选择,或者如果您碰巧打算按名称查找它们,则可能是由 name 字段键入的哈希。

  2. 您的代码对数据布局和表示做出了很多假设

    • 您的实现中的 unsigned int 类型的内存表示与二进制文件的大小、字节顺序和填充位(非)使用情况的表示相匹配。它可能确实与填充位匹配,因为它们很少使用。它可能与字节顺序有关。它可能与尺寸无关。
    • 您的实现布局了 sprites_t 类型,在 name 末尾和 n 开头之间没有任何填充。你可能在那里很幸运,但你必须如此。特别是如果您的 unsigned int 比两个字节宽,则结构布局确实包含填充的可能性很高。
  3. 灵活数组成员的灵活是指程序可以为它们提供适当的空间,而不是指它们自动伸缩。尽管您也没有阅读任何内容,但您似乎没有为您的内容提供任何空间,因此从表面上看这毫无意义。

所以,总体建议

  • 使用链表或散列,而不是数组。对于前者,我会像这样调整数据结构:

    typedef struct sprite {
        char name[11];        // includes space for a terminator
        uint16_t n;           // matches the data, except maybe in byte order
        struct sprite *next;  // to link these together into a list
        float coords[][2];    // flexible array of 2D coordinates
    } sprite_t;
    
  • 分别读取每个 Sprite 的namencoords成员

  • 最直接的方法是仅在知道有多少组坐标后才分配每个结构,所以也许

    char name[NAME_SIZE + 1] = { 0 };
    uint16_t n;
    if (fread(name, NAME_SIZE, 1, file) != 1) { /* handle EOF or I/O error ... */ }
    if (fread(&n, 2, 1, file) != 1) { /* handle EOF or I/O error ... */ }
    // swap n's byte order if appropriate ...
    sprite_t *sprite = malloc(sizeof(sprite_t) + n * sizeof(sprite->coords[0]));
    if (!sprite) { /* handle allocation failure ... */ }
    if (fread(sprite->coords, sizeof(sprite->coords[0]), n, file) != n) { /* handle EOF or I/O error ... */ }
    strcpy(sprite->name, name);
    sprite->n = n;
    append_to_linked_list(my_sprite_list, sprite);
    

即使这样,仍然假设 float 类型的实现表示与文件中使用的表示相匹配。如果没有,那么您也需要修补它。这可能需要或多或少的努力,如果尺寸不匹配,肯定会出现“更多”的情况,尽管这种情况不太可能发生。

关于c - 如何以动态排列的结构加载二进制文件的信息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56710526/

相关文章:

c - 在队列中入队/出队/插入结构

c++ - 使用 C++ 连接到 mysql

c - 我的程序不会打印,输入数字后立即关闭(C)

c - 函数在另一个函数中带有指针参数?

android - 我在哪里找到由 android 应用程序修改的文件

java - 检测文件中的行尾

c++ - 在 C++ 中创建自定义 C 类型字符串类

python - C 库中的文件句柄泄漏(也许)会给 NFS 带来麻烦(+python,但这是偶然的)

c - 在调试中得到不同的结果

c - 如何在 C 中的结构中打印三个字节