如何在结构的动态排列中加载二进制文件的信息?
How to load in a dynamic arrangement of structures the information of a binary file?
我有一个包含以下序列的二进制文件:
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 字符串是不安全的。如果您希望能够将名称视为字符串,则声明您的数组长一个字符,并使用额外的 space 确保 in-memory 副本正确终止。
除此之外,您的结构看起来不错,而且您的结构似乎是灵活数组成员的合理用例。但是所提供代码中的其他所有内容都是一场灾难。特别是,
您不能拥有具有灵活数组成员的对象数组,至少在 FAM 包含任何数据的地方不能。即使是动态数组在这里也没有意义,因为元素的大小不一致。链表将是更好的选择,或者如果您碰巧计划按名称查找它们,则可能是由 name
字段键入的散列。
您的代码对数据布局和表示做了很多假设,其中
- 您的实现的 in-memory 类型
unsigned int
表示在大小、字节顺序和填充位的(非)使用方面与二进制文件的表示相匹配。它可能确实与填充位匹配,因为它们很少使用。它可能与字节顺序有关。它可能与尺寸无关。
- 您的实施布局
sprites_t
类型,在 name
的结尾和 n
的开头之间没有任何填充。你可能在那里很幸运,但你需要如此。特别是如果您的 unsigned int
宽度超过两个字节,则结构布局确实包含填充的可能性很高。
灵活的数组成员在程序可以为他们提供适当数量的space的意义上是灵活的,而不是在space的意义上它们会自动弯曲。你似乎没有为你提供任何 space,尽管你也没有阅读任何内容,所以这在表面上没有实际意义。
所以,总体建议
使用链表或散列,而不是数组。对于前者,我会像这样调整数据结构:
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;
分别读取每个精灵的name
、n
和coords
成员
最直接的方法是在知道有多少组坐标后才分配每个结构,所以也许
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
表示与文件中使用的表示相匹配。如果没有,那么您也需要对其进行修补。这可能需要或多或少的努力,如果尺寸不匹配,"more" 肯定会出现这种情况,尽管这不太可能。
我有一个包含以下序列的二进制文件:
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 字符串是不安全的。如果您希望能够将名称视为字符串,则声明您的数组长一个字符,并使用额外的 space 确保 in-memory 副本正确终止。
除此之外,您的结构看起来不错,而且您的结构似乎是灵活数组成员的合理用例。但是所提供代码中的其他所有内容都是一场灾难。特别是,
您不能拥有具有灵活数组成员的对象数组,至少在 FAM 包含任何数据的地方不能。即使是动态数组在这里也没有意义,因为元素的大小不一致。链表将是更好的选择,或者如果您碰巧计划按名称查找它们,则可能是由
name
字段键入的散列。您的代码对数据布局和表示做了很多假设,其中
- 您的实现的 in-memory 类型
unsigned int
表示在大小、字节顺序和填充位的(非)使用方面与二进制文件的表示相匹配。它可能确实与填充位匹配,因为它们很少使用。它可能与字节顺序有关。它可能与尺寸无关。 - 您的实施布局
sprites_t
类型,在name
的结尾和n
的开头之间没有任何填充。你可能在那里很幸运,但你需要如此。特别是如果您的unsigned int
宽度超过两个字节,则结构布局确实包含填充的可能性很高。
- 您的实现的 in-memory 类型
灵活的数组成员在程序可以为他们提供适当数量的space的意义上是灵活的,而不是在space的意义上它们会自动弯曲。你似乎没有为你提供任何 space,尽管你也没有阅读任何内容,所以这在表面上没有实际意义。
所以,总体建议
使用链表或散列,而不是数组。对于前者,我会像这样调整数据结构:
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;
分别读取每个精灵的
name
、n
和coords
成员最直接的方法是在知道有多少组坐标后才分配每个结构,所以也许
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
表示与文件中使用的表示相匹配。如果没有,那么您也需要对其进行修补。这可能需要或多或少的努力,如果尺寸不匹配,"more" 肯定会出现这种情况,尽管这不太可能。