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

时间:2009-12-21 15:46:37

标签: c++ c ubuntu windows-xp filesystems

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

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

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

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

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

5 个答案:

答案 0 :(得分:15)

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

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

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

答案 1 :(得分:2)

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

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

答案 2 :(得分:2)

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

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

它有效,但它很难看。更不用说,容易出错。

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

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

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

答案 3 :(得分:1)

如果:

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

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

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

答案 4 :(得分:1)

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