Python ctypes和指针作为函数参数

2024-10-03 19:20:42 发布

您现在位置:Python中文网/ 问答频道 /正文

我编写了一个C库,通过USB接口与硬件设备连接,并成功地将该库与其他C代码一起使用,因此我知道它可以工作。我想从Python调用这个库,为了这样做,我需要通过引用传递一个结构,以便库可以修改它。结构定义如下:

typedef struct eventNode eventNode;
struct eventNode{
    int channels;
    int samples;
    uint16_t** event;
    eventNode* next;
    eventNode* prev;
}

在Python中,我定义了:

^{pr2}$

我相信这是正确的。实际上,我用它来实现一个链表,我的库可以通过调用带有签名void getFromCAEN(int, char*, eventNode**, eventNode**)的方法来修改它。最后两个参数分别指向指向列表头和表尾的指针。我的python代码通过调用以下命令创建这些指针:

queueHead = POINTER(eventNode)()
queueTail = POINTER(eventNODE)()

它最初应该为NULL(ctypes中没有),以便库知道列表是空的。当我调用这个函数时

caenlib.getFromCAEN(handle,buff,byref(queueHead),byref(queueTail))

链接列表应该由库构成,然后我尝试用以下块索引:

cur = queueHead
while cur:
    i+=1
    print("event!",i)
    print(addressof(cur))
    print(cur.contents.channels,cur.contents.samples)
    print(cur.contents.event)
    print(cur.contents.next) #print next object in line
    cur = cur.contents.next
    print(cur)               #this prints a different address for some reason

所有这些打印语句的输出是:

event! 1
140486871191712
4 150
<__main__.LP_LP_c_ushort object at 0x7fc5a60d9200>
<__main__.LP_eventNode object at 0x7fc5a60d9170>
<__main__.LP_eventNode object at 0x7fc5a60d9290>

但问题是,尽管我知道列表中应该有很多事件,但它只迭代一次,然后停止。问题似乎出在最后几行,即使cur被分配给cur.contents.next,地址在赋值之后似乎变了0x…170变成了0x…290。在这一点之后尝试取消引用cur,会引发NULL-poitner异常。我想我在Python中遗漏了一些关于指针和赋值的内容,但是我不知道该怎么做。在

PS对cur.contents.channelscur.contents.samples的访问返回的正是我所能访问的一个对象的期望值,表明它至少部分工作。在


Tags: event列表objectmaincontentsnextintsamples
1条回答
网友
1楼 · 发布于 2024-10-03 19:20:42

eventNode的ctypes定义中,next和{}被翻转了一下。所以当你使用next时,你实际上得到了NULLprev值。在

正在更改的LP_eventNode地址是不相关的。这是每次访问Structure字段时创建的Python对象的地址。在

from ctypes import *

class eventNode(Structure):
    pass

eventNode._fields_ = [
    ("channels", c_int),
    ("samples", c_int),
    ("event", POINTER(POINTER(c_uint16))),
    ("next", POINTER(eventNode)),
    ("prev", POINTER(eventNode)),
]

_fields_被定义为tuple或{},这样就保留了计算每个字段偏移量的顺序。类型中的CField描述符指定ctypes类型、大小和每个字段的偏移量。在

相关问题 更多 >