2013-05-30 60 views
3

我編寫了一個C庫來通過USB與硬件設備接口,並且已經成功地將庫與其他C代碼一起使用,所以我知道它的工作原理。我想從Python調用這個庫,爲了做到這一點,我需要通過引用傳遞一個結構,以便庫可以修改它。結構的定義:作爲函數參數的Python ctypes和指針

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的),這樣庫知道列表是空的。

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 

而所有這些的輸出:當我調用該函數與線

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

鏈表應該由圖書館,然後我通過嘗試指數具有以下塊中形成打印語句是這樣的:

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的訪問完全返回我期望它能夠訪問的一個對象,表明它至少部分工作。

回答

2

您有nextpreveventNode的ctypes定義中翻轉。因此,當您使用next時,您實際上獲得的值爲prevNULL

更改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_被定義爲一個或tuplelist使得順序被保存爲每個字段的計算偏移。該類型中的CField描述符指定每個字段的ctypes類型,大小和偏移量。

+0

謝謝!定義'_fields_'時,我不知道這個順序很重要。如果那是在文檔中,我一定錯過了它。而且我確實定義了'argtypes',我只是爲了簡潔起見而將其省略了。 – cbdumas

+0

現在我明白了,爲什麼會這樣呢,'struct'的原始聲明對Python來說是不可見的。再次感謝。 – cbdumas