【问题标题】:How to load in a dynamic arrangement of structures the information of a binary file?如何以动态排列的结构加载二进制文件的信息?
【发布时间】:2019-11-04 17:21:30
【问题描述】:

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

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?并在此基础上,利用文件提供的信息完成建筑结构。

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

【问题讨论】:

    标签: c file struct binary fread


    【解决方案1】:

    如果您的二进制 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;
      
    • 分别读取每个精灵的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 类型的实现表示与文件中使用的表示相匹配。如果没有,那么你也需要修补它。这可能需要或多或少的努力,如果尺寸不匹配,肯定会出现“更多”的情况,尽管这不太可能。

    【讨论】:

    • 非常感谢!这正是我所需要的。真的,非常感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-08
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    • 2019-10-01
    • 1970-01-01
    相关资源
    最近更新 更多