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

问题描述 投票:6回答:5

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

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

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

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

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

c++ c ubuntu windows-xp filesystems
5个回答
15
投票

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

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

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


2
投票

二进制文件应该在具有相同字节顺序的计算机之间兼容。

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


2
投票

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

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

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

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

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

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


1
投票

如果:

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

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

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


1
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.