如何在Python3中为ctypes定义的零长度数组赋值

时间:2019-12-04 09:21:24

标签: python arrays ctypes zero

在这里,我有一个如下所示的类,其属性data是一个零长度数组。如何实例化此类?

class Frame(ctypes.Structure):
    _fields_ = [
        ("id", ctypes.c_uint64),
        ("size", ctypes.c_uint32),
        ("data", ctypes.c_byte*0)       # zero-length array
    ]

我尝试过

frame = Frame()
frame.id = 0
frame.size = 2
frame.data = ctypes.cast(b'12', ctypes.POINTER(ctypes.c_type * 0))

但第4行出现了异常

TypeError: incompatible types, LP_c_byte_Array_0 instance instead of c_byte_Array_0 instance

那么,如何正确实例化此类?

1 个答案:

答案 0 :(得分:1)

列出[Python 3.Docs]: ctypes - A foreign function library for Python

此技术(具有 0 长数组作为最后一个成员的 struct )通常用于 C 中,以获取可变数据在 struct 之后。
不幸的是, Python 层不允许这样做(将大于其长度的值分配给数组)。与您的目标最接近的事情是将 data 成员声明为指针。更进一步,创建一个执行所有转换的setter方法:

code00.py

#!/usr/bin/env python3

import sys
import ctypes as ct


class Frame(ct.Structure):
    _fields_ = [
        ("id", ct.c_uint64),
        ("size", ct.c_uint32),
        ("data", ct.POINTER(ct.c_ubyte)),  # Make it a pointer
    ]

    def set_data(self, value):
        if not isinstance(value, (bytes,)):
            raise ValueError("Bytes expected.")
        self.data = ct.cast(value, ct.POINTER(ct.c_ubyte))
        self.size = len(value)


def main():
    frame = Frame()
    frame.set_data(b"123abCD")
    for i in range(frame.size):
        print("{0:d} - {1:d}".format(i, frame.data[i]))


if __name__ == "__main__":
    print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    main()
    print("\nDone.")

输出

[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q059172596]> "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\Scripts\python.exe" code00.py
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 64bit on win32

0 - 49
1 - 50
2 - 51
3 - 97
4 - 98
5 - 67
6 - 68

Done.