我正在尝试编写一个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位长)。
该死的,你这些人很快。
帕特里克,我最初开始使用struct包但发现它只是减缓我需求的方法。另外,我一直在寻找编写Python扩展的借口。我知道这是一个愚蠢的问题,但我需要注意哪些类型?
感谢。
答案 0 :(得分:3)
明确指定您的数据类型(例如整数)是32位。否则,如果在读取它们时有两个整数,它们将被读作一个64位整数。
当您处理跨平台问题时,需要注意的两个主要事项是:
0x0000000C
)将被读作201326592(0x0C000000
)。希望这有帮助。
答案 1 :(得分:2)
'struct'模块应该能够做到这一点,尽管数据中间的结构对齐始终是个问题。然而,要做到这一点并不是很难:找出(一次)结构中的结构对齐的边界,然后用手工填充(用'x'说明符)到该边界。您可以通过将struct.calcsize()与实际数据进行比较来双击填充。它肯定比为它编写C扩展更容易。
为了继续使用Py_BuildValue(),你有两个选择。您可以在编译时确定time_t的大小(根据基本类型,所以'int'或'a long'或'ssize_t')然后使用正确的格式字符到Py_BuildValue - 'i'表示int, 'l'为长,'n'为ssize_t。或者您可以手动使用PyInt_FromSsize_t(),在这种情况下,编译器会为您执行向上转换,然后使用“O”格式字符将结果传递给Py_BuildValue。
答案 2 :(得分:2)
您需要确保为结构使用体系结构独立成员。例如,int在一个架构上可以是32位而在另一个架构上可以是64位。正如其他人所建议的那样,请使用int32_t
样式类型。如果你的struct包含未对齐的成员,你可能还需要处理编译器添加的填充。
跨架构数据的另一个常见问题是字节序。英特尔i386架构是小端的,但是如果你在一台完全不同的机器上阅读(例如Alpha或Sparc),你也必须担心这一点。
Python struct模块使用作为格式字符串一部分传递的前缀来处理这两种情况。
- Big-endian标准尺寸/对齐
一般情况下,如果数据从您的机器中消失,您应该将字节顺序和大小/填充格式确定为特定的 - 即。使用“<”或“>”作为你的格式。如果要在C扩展中处理此问题,可能需要添加一些代码来处理它。
答案 3 :(得分:1)
您阅读二进制数据的代码是什么?确保您将数据复制到适当大小的类型,例如int32_t
,而不仅仅是int
。
答案 4 :(得分:0)
为什么不使用struct包?