gpt4 book ai didi

Python ctypes 位域

转载 作者:太空狗 更新时间:2023-10-30 01:29:19 24 4
gpt4 key购买 nike

我需要一个与 ctypes 结构兼容的位域定义,这样我就可以将它用作指向一组内存映射的硬件寄存器的指针,即

class RegFile(Structure):
_fields_ = [
('ticks', c_uint32),
('id', id_bitfield),
]

理想情况下,它们是非常 Pythonic 的东西,并且表现得像字典。我已经设法处理了大部分血淋淋的细节,现在我有了一个工厂函数,它可以像制作命名元组一样制作位域类。下面是一个拆分标准 float 字段的示例。

def make_register(name, fields, basetype=c_uint32):
# Define the underlying bitfield type
bitfield = type(name + '_bitfield', (LittleEndianStructure, ), {})
bitfield._pack_ = 1
bitfield._fields_ = fields

# Set up the union
d = {
'_fields_' : [('base', basetype), ('_b', bitfield)],
'_anonymous_' : ('_b',),
'__iter__' : _register_iter,
'keys' : _register_keys,
'items' : _register_items,
'update' : _register_update
}
return type(name, (Union, ), d)

ieee754_fields = [
('mantissa', c_uint, 23),
('exponent', c_uint, 8),
('sign', c_uint, 1)
]
IEEE754 = make_register('IEEE754', ieee754_fields, c_float)
x = IEEE754()

这工作得体,但不是特别 Pythonic 感觉的语法。理想情况下,我会有一些答案允许我将位域类定义为:

class IEEE754(Register):
"""Individual bitfields of a standard IEEE-754 floating point number."""
_fields_ = ieee754_fields
_basetype_ = c_float

但我一直没能使 Register 类成为现实。看起来 Register 应该继承自 Union 并应用一些元类魔法,但元类与 Union 的冲突就在于此。有什么想法吗?还是我应该坚持使用现有的东西?

最佳答案

您可以通过创建一个扩展 type(ctypes.Union) 的 Register 元类来实现您所描述的内容,如下所示:

class Register(type(ctypes.Union)):
def __new__(mcs, name, bases, dict):
#make the bitfield class
class regBitfield(ctypes.LittleEndianStructure):
_fields_ = dict['_fields_']
#set up the Union
class regUnion(ctypes.Union):
_fields_ = [('base', dict['_basetype_']), ('_b', regBitfield)]
_anonymous_ = ('_b', )
__iter__ = _register_iter
keys = _register_keys
items = _register_items
update = _register_update
#return a subclass of the temporary regUnion class
return type(ctypes.Union).__new__(mcs, name, (regUnion,), dict)

class IEEE754: #for Python3 use class IEEE754(metaclass=Register):
__metaclass__ = Register #omit this line Python3
_fields_ = [('mantissa', ctypes.c_uint, 23),
('exponent', ctypes.c_uint, 8),
('sign', ctypes.c_uint, 1)
]
_basetype_ = ctypes.c_float

这与您的 make_register 函数的工作方式几乎相同,但利用类系统的现有机制和扩展 ctypes.Unionctypes.结构。具体来说,ctypes.Unionctypes.Structure 子类的任何子类都将扩展 _fields_ 列表,而不是而不是更换它。知道这一点,我们可以在最终类扩展的 Register 元类的 __new__ 中创建临时类。有了以上:

>>> myFloat = IEEE754(42.0)
>>> print(myFloat.base)
42.0
>>> print(myFloat.mantissa)
2621440L
>>> fltReg._fields_
[('mantissa', <class 'ctypes.c_ulong'>, 23), ('exponent', <class 'ctypes.c_ulong'>, 8), ('sign', <class 'ctypes.c_ulong'>, 1)]

如果正在创建的类型具有多个基数,则 Register.__new__ 方法可能会中断。

关于Python ctypes 位域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20380451/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com