Python ctypes:具有位字段初始化的结构

时间:2018-06-15 17:09:10

标签: python structure ctypes bit-fields

我注意到我无法默认初始化ctypes.Structure派生类的对象,当它有位字段时,但我可以默认初始化这些对象的数组。

假设我们定义了这样一个类:

class What(ctypes.Structure):
    _fields_ = [('x', ctypes.c_float), ('y', ctypes.c_short, 2)]

    def __init__(self, x=None, y=None):
        if not x:
            x = ctypes.c_float()
        if not y:
            y = ctypes.c_short()
        super(What, self).__init__(x, y)

现在这段代码顺利执行,据我所知,它使用了上面定义的默认构造函数。

what_arr = What * 4
w_arr = what_arr()

返回零填充结构数组。但是,当我尝试初始化一个对象时,出现“访问冲突读取位置”错误,程序崩溃。

w = What()

如果有人解释了幕后的内容以及这种行为的原因,那将是很好的。

更多细节:

我需要

x = ctypes.c_float()
y = ctypes.c_short()

而不是直接将0传递给初始化,因为通常结构的字段包含其他结构,我也想在这里使用它们的默认构造函数(所以所有内容都以0s递归初始化)。

我相信这对于那些想要先用虚拟值测试一些包裹包的人来说可能很有用。

1 个答案:

答案 0 :(得分:1)

基类不知道xy是什么。如果我正确理解了OP,那么ctypes.Structure的默认行为就是所需要的。我添加了__repr__函数,以便更轻松地查看正在发生的事情:

class What(ctypes.Structure):
    _fields_ = [('x', ctypes.c_float), ('y', ctypes.c_short, 2)]

    def __repr__(self):
        return f'What(x={self.x},y={self.y})'

...测试

>>> w = What()
>>> w
What(x=0.0,y=0)
>>> w = What(1.5)
>>> w
What(x=1.5,y=0)
>>> w = What(1.5,2)
>>> w
What(x=1.5,y=-2)
>>> wa = (What*4)()
>>> list(wa)
[What(x=0.0,y=0), What(x=0.0,y=0), What(x=0.0,y=0), What(x=0.0,y=0)]

另请注意,默认情况下ctypes结构是零初始化的,所以即使嵌套结构也不需要任何魔法:

import ctypes

class Inner(ctypes.Structure):
    _fields_ = [('a',ctypes.c_int),('b',ctypes.c_int)]

    def __repr__(self):
        return f'Inner(a={self.a},b={self.b})'

class What(ctypes.Structure):
    _fields_ = [('x', Inner), ('y', ctypes.c_short, 2)]

    def __repr__(self):
        return f'What(x={self.x},y={self.y})'

...测试

>>> w = What()
>>> w
What(x=Inner(a=0,b=0),y=0)
>>> wa = (What*4)()
>>> list(wa)
[What(x=Inner(a=0,b=0),y=0), What(x=Inner(a=0,b=0),y=0), What(x=Inner(a=0,b=0),y=0), What(x=Inner(a=0,b=0),y=0)]