【问题标题】:Python ctypes: structure with bit fields initializationPython ctypes:具有位域初始化的结构
【发布时间】:2018-06-15 17:09:09
【问题描述】:

我注意到当 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 传递给初始化,因为通常结构的字段包含其他结构,我也想在这里使用它们的默认构造函数(这样所有东西都用 0 递归初始化)。

我相信这对于想要首先测试一些带有虚拟值的包装包的人可能很有用。

【问题讨论】:

    标签: python structure ctypes bit-fields


    【解决方案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)]
    

    【讨论】:

    • 天哪。非常感谢你。当使用位字段与不使用位字段时,您对构造函数的先前行为有任何解释吗?是不是 init 方法传递了已经构造的 ctypes.c_short 对象,不能调整大小或类似的东西?
    • @JakubŁanecki 你之前的构造函数在不知道xy 的基类上调用super()
    • 我不认为这是正确的。当我从 fields 中删除位域规范时,单个对象的初始化和数组都可以正常工作,仅位域会出现问题。另外,我相信给super() 提供子类的名称(这就是我们所做的)就足以让它了解xy
    猜你喜欢
    • 1970-01-01
    • 2010-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多