我写了一个C库来通过USB与硬件设备连接,并且已经成功地将库与其他C代码一起使用,所以我知道它有效。我想从Python调用这个库,为了做到这一点,我需要通过引用传递一个struct,以便库可以修改它。结构定义如下:
typedef struct eventNode eventNode;
struct eventNode{
int channels;
int samples;
uint16_t** event;
eventNode* next;
eventNode* prev;
}
在Python中我定义了:
class eventNode(Structure):
pass
eventNode._fields_ = [("channels", c_int),
("samples", c_int),
("event",POINTER(POINTER(c_uint16))),
("prev",POINTER(eventNode)),
("next",POINTER(eventNode))]
我认为是正确的。基本上我用它来实现一个链表,我的库可以通过调用签名为void getFromCAEN(int, char*, eventNode**, eventNode**)
的方法来修改它。最后两个参数分别是指向列表头部和尾部的指针。我的python代码通过调用:
queueHead = POINTER(eventNode)()
queueTail = POINTER(eventNODE)()
最初应为NULL(ctypes中为None),以便库知道列表为空。当我用行
调用此函数时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.channels
和cur.contents.samples
的访问完全返回了我对我能够访问的一个对象所期望的内容,表明它至少部分工作。
答案 0 :(得分:2)
您在next
的ctypes定义中翻转了prev
和eventNode
。因此,当您使用next
时,您实际上获得的NULL
值为prev
。
更改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
或list
,以便保留订单以计算每个字段的偏移量。类型中的CField
描述符指定每个字段的ctypes类型,大小和偏移量。