Python中的等效C结构

byqmnocz  于 2023-02-07  发布在  Python
关注(0)|答案(2)|浏览(158)

我在C中有以下内容:

typedef struct {
    short          Whole;
    unsigned short Frac;
} FirstStruct, FAR *pFirstStruct;

typedef struct {
    char FirstArr[3];
    FirstStruct SecondArr[3][3]
} SecStruct, FAR * pSecStruct;

我想在Python中做一些类似的事情。找到this answer解释如何使用ctypes来实现这个目的,但是我在使用SecondArr[3][3]时遇到了问题。下面是Python中的代码:

class FirstStruct(ctypes.Structure):
     _pack_ = 2
     _fields = [("Whole", ctypes.c_short),
                ("Fract", ctypes.c_ushort)]
 
 
class SecStruct(ctypes.Structure):
    class _A(ctypes.Array):
        _type_ = ctypes.c_char
        _length_ = 3

    class _B(ctypes.Array):
        _type_ = FirstStruct
        _length_ = 3

    class _C(ctypes.Array):
        _type_ = _B
        _length_ = 3

    _pack_ = 2
    _fields = [("FirstArr", _A),
               ("SecondArr", _C)]

这样做,Pylance抱怨"_B" is not defined,我不完全确定它是否有效,也不确定以这种方式混合两个子类来创建一个新的C结构是否安全。
即使Pylance抱怨,这是正确的做法吗?或者有没有其他方法来转换提到的结构?

83qze16e

83qze16e1#

根据[Python. Docs]:ctypes-数组(强调是我的):
数组是序列,包含固定数量的相同类型的示例。
创建数组类型的推荐方法是将数据类型与正整数相乘

TenPointsArrayType = POINT * 10

此外(不确定是否是 * 错字 ),对于结构,保存成员数据的属性名是**fields也以 * UnderScore结尾,而不是*_fields***(如您的情况))。
我不打算讨论代码中的问题(* NameError * s),因为它们是由误解产生的,(因此)是一个完全不同的问题。
下面是一个小例子,注意我是逐渐声明数组类型的(为了可读性),但是也可以动态声明(只在需要的地方)。
然后可以像在 * C * 中那样操作示例。

  • 代码00.py *:
#!/usr/bin/env python

import ctypes as cts
import sys

class FirstStruct(cts.Structure):
    _pack_ = 2
    _fields_ = (
        ("Whole", cts.c_short),
        ("Fract", cts.c_ushort),
    )

FirstStructPtr = cts.POINTER(FirstStruct)

CharArr3 = cts.c_char * 3
FirstStructArr3 = FirstStruct * 3
FirstStructArr3Arr3 = FirstStructArr3 * 3  # FirstStruct * 3 * 3  # Equivalent

class SecStruct(cts.Structure):
    _pack_ = 2
    _fields_ = (
        ("FirstArr", CharArr3),
        ("SecondArr", FirstStructArr3Arr3),
    )

SecStructPtr = cts.POINTER(SecStruct)

def main(*argv):
    ss = SecStruct()
    print("FirstArr:", ss.FirstArr)
    ss.FirstArr = b"XYZ"
    print("FirstArr:", ss.FirstArr, ss.FirstArr[2])
    print("SecondArr:", ss.SecondArr)
    print("SecondArr[0]:", ss.SecondArr[0])
    print("SecondArr[0][0]:", ss.SecondArr[0][0])
    print("SecondArr[0][0].Whole", ss.SecondArr[0][0].Whole)
    ss.SecondArr[0][0].Whole = 0xFF
    print("SecondArr[0][0].Whole", ss.SecondArr[0][0].Whole)

if __name__ == "__main__":
    print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
                                                   64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    rc = main(*sys.argv[1:])
    print("\nDone.\n")
    sys.exit(rc)
    • 输出**:
[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q075351547]> "e:\Work\Dev\VEnvs\py_pc064_03.10_test0\Scripts\python.exe" ./code00.py
Python 3.10.9 (tags/v3.10.9:1dd9be6, Dec  6 2022, 20:01:21) [MSC v.1934 64 bit (AMD64)] 064bit on win32

FirstArr: b''
FirstArr: b'XYZ' 90
SecondArr: <__main__.FirstStruct_Array_3_Array_3 object at 0x000001C128675F40>
SecondArr[0]: <__main__.FirstStruct_Array_3 object at 0x000001C128BDC9C0>
SecondArr[0][0]: <__main__.FirstStruct object at 0x000001C128BDC2C0>
SecondArr[0][0].Whole 0
SecondArr[0][0].Whole 255

Done.

可能还值得一读:

5vf7fwbs

5vf7fwbs2#

下面显示了用一个类型乘以一个整数来创建一个数组,但是注意C是以行为主的顺序存储数组的。要创建具有正确内存布局的数组,首先乘以列的大小来创建一个单行数组,然后乘以行的大小来完成数组。在你的例子[3][3]中,这并不重要,但是如果大小不同的话,这就很重要了,就像我特意展示的那样。
每个struct还包含一个__repr__函数,用于定义结构如何显示自身,并从连续编号的字节缓冲区创建一个示例,以说明正确的little-endian布局:

import ctypes as ct

ROWS = 3
COLS = 2

class FirstStruct(ct.Structure):
    _fields_ = (("Whole", ct.c_short),
                ("Frac", ct.c_ushort))

    def __repr__(self):
        return f'FirstStruct(Whole={self.Whole:#x}, Frac={self.Frac:#x})'

class SecStruct(ct.Structure):
    _fields_ = (("FirstArr", ct.c_ubyte * COLS),           # equivalent to FirstArr[COLS]
                ("SecondArr", FirstStruct * COLS * ROWS))  # equivalent to FirstStruct[ROWS][COLS]

    def __repr__(self):
        arr = '[' + '\n                     '.join([str(x[:]) for x in self.SecondArr]) + ']'
        return (f'SecStruct(FirstArr={self.FirstArr[:]},\n'
                f"          SecondArr={arr})")
                
s = SecStruct.from_buffer_copy(bytes(range(ct.sizeof(SecStruct))))
print(s)

输出:

SecStruct(FirstArr=[0, 1],
          SecondArr=[[FirstStruct(Whole=0x302, Frac=0x504), FirstStruct(Whole=0x706, Frac=0x908)]
                     [FirstStruct(Whole=0xb0a, Frac=0xd0c), FirstStruct(Whole=0xf0e, Frac=0x1110)]
                     [FirstStruct(Whole=0x1312, Frac=0x1514), FirstStruct(Whole=0x1716, Frac=0x1918)]])

相关问题