【发布时间】:2013-09-02 08:30:24
【问题描述】:
我正在尝试通过 TCP 从 C(实际上是 Obj-C,但面向对象不在此列)客户端向 python 服务器发送消息。现在我首先发送一个unsigned short,其中包含消息大小,然后是消息,它是一个C 结构。我想在包的末尾附加一个动态字符串,所以我决定使用结构体大小将包一分为二,但问题开始了。
问题是,要么我做错了,要么 Python 的 struct 库大小 + 填充计算存在错误。
Python struct 似乎可以正确解析填充。例如,对于这个结构:
struct.Struct("H I").size == 8
与此结构的sizeof 返回值匹配:
#include <stdio.h>
typedef struct {
unsigned short a;
unsigned int b;
} test;
int main() {
printf("%ld\n", sizeof(test));
return 0;
}
$ gcc test.c
$ ./a.out
8
但是对于某些结构定义,我并不总是得到相同的结果。例如,在这种情况下:
struct.Struct("H 5s").size == 7
typedef struct {
unsigned short a;
char b[5];
} test;
sizeof(test) == 8
我在某处读到编译器可能会填充一个结构,以确保在数组中使用结构时可以正确访问内存。我不确定是否是这种情况(似乎是),但如果是这样,我不明白为什么这个结构没有填充到 8 个字节(假设是 4 个字节的打包):
struct.Struct("H 4s").size == 6
typedef struct {
unsigned short a;
char b[4];
} test;
sizeof(test) == 6
所以,澄清一下,我的问题是如何在 Python 中获得给定结构的精确大小,因为它没有应用最终填充。
我尝试过的:
手动添加最终填充大小:
real_struct_size = self._struct.size + self._struct.size % 4
当然,这不起作用,因为单个成员结构不会添加填充,并且您可以在最后一种情况下看到它也不适用于小型结构(无符号短+字符[4])。 (也许我在这里过度简化了问题。也许这与小结构无关,而是与另一个我无法识别的因素有关。)
然后我打开了 Python 的 struct 库,看看我怎样才能知道需要多少个参数,所以我可以问它是否为 1,然后避免最后的填充,但是无法访问 @ 的 s_len 属性987654330@(参见 Python-2.7.5/Modules/_struct.c:48),这是存储打包参数数量的地方。
因此,作为一种解决方法,我在数据包的开头放置了一个偏移值,以了解额外/动态字符串的开始位置。
但我认为这里有一个错误(我的或来自 Python 的 struct 库)。无论哪种方式,如果是我,我真的需要知道我做错了什么,或者如果它是 Python 的库,我想报告这个问题。如果有人能帮助我查明真相,我将不胜感激。
所以,提前谢谢!抱歉发了这么长的帖子:)
【问题讨论】:
-
你试过使用
struct.calcsize()函数吗? -
@martineau 它给出的结果与
Struct.size(在我的机器上)相同。事实上Struct.size的文档字符串似乎是calcsize的文档字符串的副本。我不是 C 的专家,但我相信该标准并不能保证structs 的大小,所以 python cannot 在任何情况下都可以可靠地计算它。不同的编译器会添加不同的填充(我相信主要取决于架构)。 -
文档还说“要将结构的末尾与特定类型的对齐要求对齐,请以该类型的代码结束格式,重复计数为零”,所以也许你可以做这样的事情。还要确保使用两种本机类型(
@或=)之一作为格式字符串的前缀,否则将不会添加任何填充。 -
嗯,这不是自动的,而是更好的解决方法,我会试一试,谢谢!关于前缀,例如“如果第一个字符不是其中之一,则假定为'@'。”我会在这里尝试更新:)
-
@martineau 遗憾的是添加 0 不会影响大小计算。还是谢谢!
标签: python c python-2.7 struct