【问题标题】:Reading 32bit Packed Binary Data On 64bit System在 64 位系统上读取 32 位打包二进制数据
【发布时间】:2010-09-13 05:02:42
【问题描述】:

我正在尝试编写一个 Python C 扩展来读取打包的二进制数据(它存储为结构的结构),然后将其解析为 Python 对象。一切都在 32 位机器上按预期工作(二进制文件总是写在 32 位架构上),但不是在 64 位机器上。有没有“首选”的方式来做到这一点?


要发布很多代码,但作为示例:

struct
{
    WORD    version;
    BOOL    upgrade;
    time_t  time1;
            time_t  time2;
} apparms;

File *fp;
fp = fopen(filePath, "r+b");
fread(&apparms, sizeof(apparms), 1, fp);
return Py_BuildValue("{s:i,s:l,s:l}",
  "sysVersion",apparms.version,
  "powerFailTime", apparms.time1,
  "normKitExpDate", apparms.time2
 );

现在在 32 位系统上效果很好,但在 64 位上,我的 time_t 大小不同(32 位与 64 位长)。


该死的,你们这些人速度很快。

Patrick,我最初开始使用 struct 包,但发现它只是为了满足我的需要而减慢速度。另外,我正在寻找编写 Python 扩展的借口。

我知道这是一个愚蠢的问题,但我需要注意哪些类型?

谢谢。

【问题讨论】:

    标签: python c 64-bit


    【解决方案1】:

    明确指定您的数据类型(例如整数)是 32 位的。否则,如果您在读取它们时有两个相邻的整数,它们将被读取为一个 64 位整数。

    当您处理跨平台问题时,需要注意的两个主要事项是:

    1. 位数。如果您的打包数据是用 32 位整数写入的,那么您的所有代码在读取写入时都必须明确指定 32 位整数。
    2. 字节顺序。如果您将代码从 Intel 芯片移动到 PPC 或 SPARC,您的字节顺序将是错误的。您必须导入数据,然后对其进行字节翻转,以使其与当前架构相匹配。否则 12 (0x0000000C) 将被读取为 201326592 (0x0C000000)。

    希望这会有所帮助。

    【讨论】:

      【解决方案2】:

      'struct' 模块应该能够做到这一点,尽管数据中间的结构对齐总是一个问题。然而,要做到这一点并不难:找出(一次)结构中的结构对齐到哪个边界,然后填充(手动,使用'x'说明符)到那个边界。您可以通过将 struct.calcsize() 与您的实际数据进行比较来仔细检查您的填充。这肯定比为其编写 C 扩展更容易。

      为了像这样继续使用 Py_BuildValue(),您有两个选择。您可以在编译时确定 time_t 的大小(就基本类型而言,即“an int”或“a long”或“an ssize_t”),然后对 Py_BuildValue 使用正确的格式字符——“i”表示 int, 'l' 表示长,'n' 表示 ssize_t。或者您可以手动使用 PyInt_FromSsize_t(),在这种情况下,编译器会为您进行向上转换,然后使用“O”格式字符将结果传递给 Py_BuildValue。

      【讨论】:

        【解决方案3】:

        您需要确保为您的结构使用独立于架构的成员。例如,一个 int 在一种架构上可能是 32 位,而在另一种架构上可能是 64 位。正如其他人所建议的那样,请改用 int32_t 样式类型。如果您的结构包含未对齐的成员,您可能还需要处理编译器添加的填充。

        跨架构数据的另一个常见问题是字节序。 Intel i386 架构是 little-endian,但如果您在完全不同的机器(例如 Alpha 或 Sparc)上阅读,您也必须担心这一点。

        Python struct 模块使用作为格式字符串的一部分传递的前缀来处理这两种情况。

        • @ - 使用原生大小、字节顺序和对齐方式。 i= sizeof(int), l= sizeof(long)
        • = - 使用原生字节序,但使用标准大小和对齐方式(i=32 位,l=64 位)
          • 大端标准尺寸/对齐方式

        一般来说,如果数据从您的机器中传递出去,您应该将字节顺序和大小/填充格式确定为特定的内容 - 即。使用“”作为您的格式。如果你想在你的 C 扩展中处理这个,你可能需要添加一些代码来处理它。

        【讨论】:

          【解决方案4】:

          读取二进制数据的代码是什么?确保将数据复制到适当大小的类型中,例如 int32_t 而不仅仅是 int

          【讨论】:

            【解决方案5】:

            你为什么不使用struct 包?

            【讨论】:

              猜你喜欢
              • 2011-09-08
              • 1970-01-01
              • 2021-11-18
              • 1970-01-01
              • 2020-07-06
              相关资源
              最近更新 更多