二进制文件和跨平台兼容性

我编写了一个C ++库,将我的数据(自定义结构的集合等)保存到二进制文件中。 我目前在Windows(XP)机器上本地使用(即创建使用 )文件。 为简单起见,让我们将库分为两部分:一个编写器 (创建文件)和一个读者消费者 (只是从文件中读取数据)。

最近,我想在我的Linux机器上使用 (即读取)我在XP机器上创建的数据文件。 我必须在这个阶段指出两台机器都是PC(因此具有相同的endianess等)。

我可以构建一个阅读器(并为Linux编译[确切地说是Ubuntu 9.10]),因为我是图书馆的创建者。 我的问题,在我踏上这条道路(建立读者等)之前是:

假设我已经成功构建了Linux的阅读器,

我可以简单地将在Windows(XP)机器上创建的文件复制到Linux(Ubuntu 9.10)机器并使用Linux阅读器成功读取复制的文件吗?

对于要二进制兼容的文件:

  • 字节顺序必须匹配(就像它一样)
  • 位域包装顺序必须相同
  • 类型的大小和签名必须相同
  • 编译器必须做出有关填充和对齐的相同决定

所有这些条件当然有可能实现,或者你不会碰巧遇到任何不适合的情况。 但至少,我会添加一些健全性检查和/或哨兵成员来发现问题。

二进制文件应该在具有相同endianess的机器上兼容。

您的代码中可能存在的问题是int的大小,您不一定假设不同OS上的编译器具有相同的int大小。 因此要么复制字节块并将其转换,要么使用int16,int32等。

结构不是文件格式,您不应该尝试使用它们。

当试图使结构与freadfwrite一起工作时,有大量的黑客可以使它工作。 您使用字节交换整数,以便可以在little-endian和big-endian机器之间共享文件。 您将结构更改为使用固定宽度整数类型,因此您可以在具有不同字长的计算机之间共享(例如在x86和x64计算机之间)。 您可以添加特定于编译器的编译指示来控制结构的填充以在编译器版本之间共享。

它有效,但很难看。 更何况,容易出错。

与字节顺序谬误中的建议非常相似,更好的想法是编写代码来单独读取/写入字段。 通过编写自己的代码,可以确保没有填充,并且可以选择与整数的本地大小无关的整数大小,并且可以在不进行字节交换的情况下支持两个字节序(通过分别读取/写入整数的字节)。

与hacky方法不同,这很难出错。 此外,因为您不依赖于任何编译器或体系结构特定的行为,所以您的代码可以在所有编译器和体系结构上运行,也可以不运行。 如果你做得对,你不应该有任何特定于平台的错误。

有一个缺点; 单独读/写字段将比直接使用fread / fwrite慢。 您可以设置一个缓冲区( uint8_t buffer[] )并将整个数据写入其中,然后立即写出所有内容,这可能有所帮助,但它仍然会更慢(因为您仍然需要移动这些字段一次一个地进入缓冲区),但是对于大多数用途来说它仍然足够快(例外是嵌入式/实时系统或极高性能计算)。

如果:

  • 机器具有相同的endianess(如你所说)和
  • 你打开二进制模式的流,因为文本模式可能做有趣的事情,例如行尾和
  • 你已经编程干净,所以你不要绊倒实现定义的东西,如对齐,数据类型大小和结构打包,

然后是的,你的文件应该是可移植的。

第三个要点是使文件格式成为“便携式”文件格式的原因。 根据结构中的数据类型,它可能非常简单或有点棘手。 位域或从不同类型重新解释的数据尤其棘手。

您可以考虑查看Boost序列化库 。 已经有很多想法,它将为您处理许多潜在的跨平台不兼容问题。 当然,对于您的特定用例而言,这可能是过度的,特别是如果您已经实现了您的作者和读者。