如何将如下所示的C结构表示为python ctype并访问它?它将结构数组作为元素,并在另一个结构中使用-。
struct hello {
__s64 f1;
__u64 f2;
__u64 f3;
__s32 f4;
__u32 f5;
};
struct world {
__u64 f1;
__u64 f2;
__u16 f3;
__u16 f4;
__u32 f5;
struct hello h[0];
};我尝试了以下方法,但不起作用:
from ctypes import *
class hello(Structure):
_pack_ = 1
_fields_ = [ ("f1", c_longlong),
("f2", c_ulonglong),
("f3", c_ulonglong),
("f4", c_long),
("f5", c_ulong)
]
class world(Structure):
_pack_ = 1
_fields_ = [ ("f1", c_ulonglong),
("f2", c_ulonglong),
("f3", c_uint16),
("f4", c_uint16),
("f5", c_uint32),
("f6", hello) #Is this correct?
]发布于 2018-07-27 09:12:47
你所做的是不正确的。要使world的最后一个成员成为N个hello的数组,它的类型必须是hello * N,而不是hello。
但在这里,N是0,所以这并不是真的有效。
在C中,这被称为"struct hack“或"struct array hack”。该world结构不是一个真正的结构,您可以按原样构造并传递它。相反,您要做的是非法锁定sizeof(world) + N * sizeof(hello)字节,将其转换为world *,然后传递该指针。因为数组索引在C中不做任何类型检查,所以my_world->h[2]将会正常工作(假设您在world的末尾至少为3个hello分配了足够的内存)。
但它在Python中不起作用。
嗯,这是可行的,但你必须做更多的工作。
第一种选择是不在全局范围内实际定义world,而是在每次需要处理world时定义一个新的Structure类。
例如。假设我们调用了一些函数,告诉我们有多少个hello:
n = lib.number_of_hellos()现在我们想调用一个函数,它给我们提供了一个包含那么多问候的世界。所以:
class world(Structure):
_pack_ = 1
_fields_ = [ ("f1", c_ulonglong),
("f2", c_ulonglong),
("f3", c_uint16),
("f4", c_uint16),
("f5", c_uint32),
("f6", hello * n)
]此时,您可以更改lib.get_world的restype以返回POINTER(world),也可以转换返回的结果。
或者,您可以将world定义为始终具有1个hello,但是随后,不是直接从world指针访问hello,而是在hello的地址(或仅在world的地址加上类型的hello的偏移量;这两种方式都是相同的)处构造一个hello * N指针。
如果您需要创建一个包含N个hello的world来传递给C,该怎么办?
您可以再次使用第一个技巧,构造一个以N个hellos数组结尾的新world类,然后创建该类的一个实例将其传递给C。
或者,您可以使用C代码使用的相同技巧:保留全局单hello world类,然后通过创建缓冲区然后将其强制转换为world来构造world对象,或者通过构造world对象然后在其上调用resize来构造。
还有一些变通方法可以让你的生活更轻松。例如,如果您自己编写C代码(并且不能直接使用struct hack),那么可以很容易地将一对C函数添加到N-hello world中,反之亦然,这对C函数组成一个非hello数组、一个hello数组和一个world。
或者,只需创建一个nonhackyworld类型,在末尾有一个指向hellos数组的指针,而不是直接包含它,然后编写C函数在它们之间来回转换。
然后,您只需对这些函数执行ctypes操作,并在需要传递或处理world时调用它们(或者甚至将它们设置为其他函数的值类型转换器)。
即使你不能添加C函数,你也可以用ctypes编写这些函数。它们将是创建缓冲区和强制转换指针的可怕丑陋的混乱,但您只需编写它们(并调试段错误)一次,然后到处使用它们。
https://stackoverflow.com/questions/51549340
复制相似问题