我想将结构数据输出到二进制文件,但每个变量的信息之间没有任何填充位。例如:
struct s {
int i1;
short s1;
char c1;
};
struct s example[2];
如果我使用fwrite(&example, sizeof(struct s), 2, file)
,则二进制文件仍然具有填充位,例如s1
和c1
,以及c1
到{{1}之间的填充位}。
从输出文件中删除这些填充位的好方法是什么?
谢谢!任何帮助表示赞赏
答案 0 :(得分:5)
我建议单独手动读取/写入结构的成员。使用编译器指令进行打包可能会导致未对齐数据访问的低效率和可移植性问题。如果你必须处理字节序,那么稍后当你的阅读操作分解为字段成员而不是整个结构时,它很容易支持。
另一件事,这与未来的维护类型问题有关,就是你不希望你的序列化代码或人们迄今为止保存的文件如果你稍微更改结构就会中断(添加新元素)或甚至将订单更改为缓存行优化,例如)。因此,与使用直接将结构的内存内容直接转储到文件中提供更多喘息空间的代码相比,您可能会遇到更少的痛苦,并且它通常最终值得努力序列化你的成员个人。
如果你想概括一个模式并减少你编写的样板数量,你可以做一些这样的事情作为开始和构建的基本例子:
struct Fields
{
int num;
void* ptrs[max_fields];
int sizes[max_fields];
};
void field_push(struct Fields* fields, void* ptr, int size)
{
assert(fields->num < max_fields);
fields->ptrs[fields->num] = ptr;
fields->sizes[fields->num] = size;
++fields->num;
}
struct Fields s_fields(struct s* inst)
{
struct Fields new_fields;
new_fields.num = 0;
field_push(&new_fields, &inst->i1, sizeof inst->i1);
field_push(&new_fields, &inst->s1, sizeof inst->s1);
field_push(&new_fields, &inst->c1, sizeof inst->c1);
return new_fields;
}
现在你可以使用这个Fields
结构和通用函数来读写任何结构的成员,如下所示:
void write_fields(FILE* file, struct Fields* fields)
{
int j=0;
for (; j < fields->num; ++j)
fwrite(fields->ptrs[j], fields->sizes[j], 1, file);
}
这通常比一些接受回调的功能for_each_field
方法更容易使用。
现在,你需要担心的是,当你创建一个新的结构S
时,要定义一个函数来从一个实例输出struct Fields
,然后启用你编写的所有那些通用函数struct Fields
即可自动使用此新S
类型。
答案 1 :(得分:1)
许多编译器接受命令行参数,这意味着&#34;打包结构&#34;。此外,许多人接受一个pragma:
#pragma pack(1)
其中1表示字节对齐,2表示16位字对齐,4表示32位字对齐等。
答案 2 :(得分:1)
要使您的解决方案平台独立,您可以创建一个函数,一次写入struct
一个字段,然后调用该函数根据需要写入struct
个
int writeStruct(struct s* obj, size_t count, FILE* file)
{
size_t i = 0;
for ( ; i < count; ++i )
{
// Make sure to add error checking code.
fwrite(&(obj[i].i1), sizeof(obj[i].i1), 1, file);
fwrite(&(obj[i].s1), sizeof(obj[i].s1), 1, file);
fwrite(&(obj[i].c1), sizeof(obj[i].c1), 1, file);
}
// Return the number of structs written to file successfully.
return i;
}
用法:
struct s example[2];
writeStruct(s, 2, file);