在C中转储结构

时间:2011-05-13 01:21:22

标签: c binaryfiles

使用fwrite简单地将结构转储到二进制文件是一个好主意吗? e.g

  struct Foo {
     char name[100]; 
     double f;
     int bar; 
  } data;

   fwrite(&data,sizeof(data),1,fout);

它有多便携? 我认为抛出编译器给出的任何内容(填充,整数大小等等)真是个坏主意。即使平台可移植性不重要。

我有一位朋友认为这样做很常见......在实践中。 这是真的???

编辑:编写可移植二进制文件的推荐方法是什么?使用某种库? 我对如何实现这一点感兴趣。(通过指定字节顺序,大小,......?)

4 个答案:

答案 0 :(得分:3)

这当然是一个非常糟糕的主意,原因有两个:

  • 由于对齐问题和编译器情绪,同一struct在不同平台上可能会有不同的大小
  • struct的元素在不同的机器上可能有不同的表示形式(想想big-endian / little-endian,IEE754与其他一些东西,sizeof(int)在不同的平台上)

答案 1 :(得分:3)

您是否希望文件是可移植的,或仅仅是代码,这一点非常重要。

如果你只是想在相同的C实现上读取数据(这意味着对于任何影响结构布局的编译器选项具有相同的值),使用相同的结构定义,那么代码是可移植的。由于其他原因可能是一个坏主意:更改结构的困难,理论上可能存在将填充字节转储到磁盘或在该字符串数组中的任何NUL终结符之后的字节的安全风险。它们可能包含您从未打算坚持的信息。也就是说,操作系统在交换文件中一直这样做,所以不管怎样,但是当用户注意到你的文档格式并不总是删除他们认为已删除的数据时,请尝试使用这个借口,他们只是通过电子邮件将其发送给了记者。

如果文件需要在不同的平台之间传递,那么这是一个非常糟糕的主意,因为你不小心将文件格式定义为“Win32上的MSVC最终写入”。这可能最终在其他平台上读取和写入非常不方便,当然,当您在具有不兼容的结构存储表示的另一个平台上运行时,您首先编写的代码将无法执行此操作。

推荐按优先顺序编写可移植二进制文件的方法可能是:

  1. 别。使用文本格式。准备好在浮点值上失去一些精确度。
  2. 使用图书馆,虽然这里有一点选择的诅咒。您可能认为ASN.1看起来很好,只要您自己永远不必操纵这些东西。我猜想Google Protocol Buffers相当不错,但我自己从未使用它。
  3. 根据每个unsigned char的含义来定义一些相当简单的二进制格式。这对于字符[*]和其他整数来说很好,但对于浮点类型来说有点棘手。 “这是IEEE-754浮点数的小端表示”,只要您的所有目标平台都使用IEEE浮点数,它就可以。我希望他们这样做,但你必须打赌。然后,组合该字符序列进行编写并将其解释为:如果您“幸运”,那么在给定平台上,您可以编写完全匹配它的结构定义,并使用此技巧。否则,请执行您需要的任何字节操作。如果您想要真正可移植,请注意不要在代码中使用int来表示从bar获取的值,因为如果您在int为16的某个平台上执行此操作比特,它不适合。而是使用longint_least32_t或其他东西,然后检查写入时的值。或者使用uint32_t并让它换行。
  4. [*]直到你点击EBCDIC机器,就是这样。并不是说任何人都会认真地希望你的文件能够移植到纯文本文件不可移植到的机器上。

答案 2 :(得分:1)

你是否喜欢在半夜接听电话?使用#pragma打包它们或者用变量写它们变量。

答案 3 :(得分:1)

是的,这种愚蠢是非常普遍的,但这并不是一个好主意。您应该按指定的字节顺序单独编写每个字段,这样可以避免对齐和字节顺序问题,但需要花费一点点额外的工作量。逐字段读取和写入也会使您在升级软件时更加轻松,并且必须阅读旧数据格式或底层硬件架构发生变化。