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

我写了一个C ++库,将我的数据(一组定制结构等)保存到二进制文件中。 我目前在Windows(XP)机器上使用(即创build使用 )本地文件。 为了简单起见,让我们将库分为两部分:一个writer (创build文件)和一个readerconsumer (简单地从文件中读取数据)。

最近,我还想在我的Linux机器上使用 (即读取)我在XP机器上创build的数据文件。 在这个阶段我必须指出,这两台机器都是个人电脑(所以有相同的endianess等)。

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

假设我成功构build了Linux的阅读器,

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

为了使文件是二进制兼容的:

  • endianness必须匹配(就像它为你)
  • 位域打包顺序必须相同
  • 类型的大小和符号必须相同
  • 编译器必须对填充和对齐做出相同的决定

所有这些条件都可以被满足,或者你不会碰到任何不适合的情况。 不过,至少我会添加一些理智检查和/或哨兵成员来发现问题。

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

你在代码中可能遇到的问题是整数的大小,你不一定认为不同操作系统上的编译器具有相同的大小int。 所以无论是复制字节块并转换它们,还是使用int16,int32等

如果:

  • 机器具有相同的永久性(正如你所说的那样)和
  • 你在二进制模式下打开流,因为文本模式可能会做一些有趣的事情,比如线端和
  • 你已经编程干净,所以你不要偶然碰到实现定义的东西,如路线,数据类型的大小和结构打包,

那么是的,你的文件应该是可移植的。

第三个要点是使文件格式成为“便携式”格式。 根据结构中的数据类型,它可能非常容易或者有点棘手。 位字段或从不同类型重新解释的数据特别棘手。

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

结构不是一种文件格式,你不应该尝试像这样使用它们。

当试图使freadfwrite工作的结构,有大量的黑客使其工作。 您可以使用字节交换整数,以便在小端和大端机器之间共享文件。 您将结构更改为使用固定宽度整数类型,以便您可以在不同字大小的机器(如x86和x64机器之间)之间共享。 您可以添加编译器特定的编译指示来控制结构的填充以在编译器版本之间共享。

它的工作,但它是丑陋的。 更何况,容易出错。

就像字节顺序谬误中的建议一样,更好的办法是编写代码来单独读/写字段。 通过编写自己的代码,可以确保没有填充,并且可以独立于本地整数大小选择整数大小,并且可以在不进行字节交换的情况下(通过单独读取/写入整数字节)支持两个字节序列。

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

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