3

我正在尝试通过 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属性PyStructObject(参见 Python-2.7.5 /Modules/_struct.c:48) 这是存储打包参数数量的地方。

因此,作为一种解决方法,我在数据包的开头放置了一个偏移值,以了解额外/动态字符串的开始位置。

但我认为这里有一个错误(我的或来自 Python 的 struct 库)。无论哪种方式,如果是我,我真的需要知道我做错了什么,或者如果它是 Python 的库,我想报告这个问题。如果有人可以帮助我弄清楚这一点,我将非常感激。

所以,提前谢谢!对不起,很长的帖子:)

4

2 回答 2

1

简短的回答:你不能。struct 模块仅通过重用基本类型的一些符号来与 C 类型相关,以方便程序员。所有与填充相关的修复都会在您将代码移动到不同平台、由另一个编译器编译的代码或其他任何东西时中断。

获取结构(c-struct)大小的唯一方法是从 C 中引用它并使用编译器编译该代码。您可以使用像

return PyInt_FromLong(sizeof(mystruct));

长答案:实现一些包装代码,#includes 适当的类型,将它们写入内存并传递它们(作为不透明对象)。你可以实现 bufferview 协议,这样你就可以将它直接传递给 socket.send()

于 2013-08-29T19:27:04.320 回答
1

要将结构的末尾对齐到对齐要求,我们只需要找到最大的整数类型。像这样的东西:

def c_sizeof(s):
    # Types sorted in size order
    size_map = "cbB?hHiIlLqQfd"
    # Filter out chars in s that not in size_map.
    # The default align char ("c") in case filtered list is empty.
    chars = filter(lambda x: x in size_map, s) + "c"
    # Largest index and its char in size_map gives the align char
    align_char = size_map[max([size_map.index(x) for x in chars])]
    # Using native prefix to calculate alignment between fields
    return struct.calcsize("@{0}0{1}".format(s, align_char))

并运行一些测试

print c_sizeof("cci"), c_sizeof("cic"), c_sizeof("H5s")

生产

8 12 8
于 2019-10-07T22:07:21.390 回答