Python 结构体分配具有类型安全的位域

问题描述 投票:0回答:1

考虑我有以下结构:

import ctypes

class MyStruct(ctypes.BigEndianStructure):
    # ! These typehints are added so that the IDE recognizes the fields of the Structure
    field_size1: ctypes.c_uint8
    field_size7: ctypes.c_uint8
    field_size8: ctypes.c_uint8

    _pack_ = 1
    _fields_ = [
        ("field_size1", ctypes.c_uint8, 1),
        ("field_size7", ctypes.c_uint8, 7),
        ("field_size8", ctypes.c_uint8, 8),
    ]

我能够从 Python 类型分配此结构中的位并获取我期望的字节。

s = MyStruct()
s.field_size1 = 1
s.field_size7 = 2
s.field_size8 = 3

我收到 mypy linting 错误:

Incompatible types in assignment (expression has type "int", variable has type "c_uint8") Mypy(assignment)

但是,如果我尝试使用

ctype
,程序就会崩溃(即不打印下面的消息):

s = MyStruct()
s.field_size1 = ctypes.c_uint8(1)
print("completed")

这正是我所期望的。尝试将 8 位压缩为 1 位长度是没有意义的。

在分配位域时是否有正确的方法来使用

ctypes
类型以使 Python 和 mypy 都满意而不会“类型忽略”

python ctypes
1个回答
0
投票

感谢@Mark Tolonen

我能够更好地理解我的问题并得出这个答案。

这些

ctypes.Structure
对象会自动处理到本机 Python 类型的转换。

以原来的例子

>> print(type(s.field_size1))
<class 'int'>
>> s.field_size7 = -20
>> print(s.field_size7) # We also get overflow behaviour as we expect from C
206

我的困惑源于我涉及数组的实际用例,因为它们本身不会被转换。因此,当我使用原始应用程序时,我天真地将示例逻辑应用于数组和其他字段。

import ctypes

ARRAY_SIZE = 5
UINT8x5_ARRAY = ctypes.c_uint8 * ARRAY_SIZE


class MyStructWithArray(ctypes.BigEndianStructure):

    _pack_ = 1
    _fields_ = [
        ("field_size1", ctypes.c_uint8, 1),
        ("field_size7", ctypes.c_uint8, 7),
        ("field_size8x5", UINT8x5_ARRAY),
    ]

现在

>> s = MyStructWithArray(1,2,UINT8x5_ARRAY(*list(range(5,5+ARRAY_SIZE))))
>> print(type(s.field_size1))
<class 'int'>
>> print(type(s.field_size8x5))
<class '__main__.c_ubyte_Array_5'>

现在我需要回答的问题是如何最好地输入提示数组。

这也和元组直接赋值一样简单,并且元组可以在类型提示中具有特定的长度:

import ctypes

ARRAY_SIZE = 5
UINT8x5_ARRAY = ctypes.c_uint8 * ARRAY_SIZE

class MyStructWithArray(ctypes.BigEndianStructure):
    # ! These typehints are added so that the IDE recognizes the fields of the Structure
    field_size1: int
    field_size7: int
    field_size8x5: tuple[int, int, int, int, int]

    _pack_ = 1
    _fields_ = [
        ("field_size1", ctypes.c_uint8, 1),
        ("field_size7", ctypes.c_uint8, 7),
        ("field_size8x5", UINT8x5_ARRAY),
    ]


>> s.field_size8x5 = (0,1,2,3,4)
>> print(list(s.field_size8x5)) # printing is trivial as can also be casted to a native type
[0,1,2,3,4]
>> print(s.field_size8x5[6]) # mypy[misc]: Tuple index out of range

© www.soinside.com 2019 - 2024. All rights reserved.