2017-03-24 29 views
0

我試過閱讀關於此主題的所有問題/答案,但我無法獲得任何工作。我所要做的就是將結構發送到共享對象,然後讓它返回並可訪問。Ctypes:將返回的指針映射到結構

我已經成功創建了一個結構,我可以很好地將它傳遞給共享對象。我知道這一點,因爲如果從結構中返回一個特定值,它可以正常工作。 Python中的結構定義可以看到下面:

class ROW(ctypes.Structure): 
    _fields_ = [("Address",ctypes.c_int16), 
       ("FirstRegister",ctypes.c_int16), 
       ("NumberOfRegisters",ctypes.c_int16), 
       ("Sampling", ctypes.c_int16)] 

class CONNECTOR(ctypes.Structure): 
    _fields_ = [("NumberOfRows", ctypes.c_int16), 
       ("Rows", ROW * 200)] 

# Initialise an array of connectors (CON1, CON2, CON11, CON12) 
ConArray = CONNECTOR * 4 
con = ConArray() 

# Initialise an array of ROW struct 
RowArray = ROW * 200 
row = RowArray() 

我再從SQLite數據庫中的數據填充結構,並且可以使用訪問特定數據con[n].Rows[m].Address

目前我正在試圖只發送一個一次連接器,並返回完全相同的結構。

相關的代碼可以看到下面:

testlib = ctypes.cdll.LoadLibrary('_example.so') 
x = testlib.square_array 
x.argtype = ctypes.POINTER(CONNECTOR) 
x.restype = ctypes.POINTER(CONNECTOR) 

y = x(ctypes.byref(con[0])) 

我曾嘗試調用的函數的許多不同的方法,但這個似乎是最有前途的。問題是當我嘗試使用y.Rows[0].Address[0]訪問特定值時,發生錯誤:AttributeError: 'LP_CONNECTOR' object has no attribute 'Rows'

如果不是,我只是直接調用該函數:

x = testlib.square_array(ctypes.byref(con[0])) 

我收到int我以爲代表的內存地址,例如:35664848

我已經嘗試了各種選擇,但我很不熟悉C(一個同事將處理代碼的所有C端)。有沒有建議的解決方案?我覺得我只是想念一件小事,但爲了達到這一點,我花了很多天。

更新:添加C代碼

C代碼可以如下所示:

example.c:

#include "example.h" 

CONNECTOR* square_array(CONNECTOR* con) 
{ 
    printf("Value of Row 0 Address%i\n",con->Rows[0].Address); 
    return (con); 
} 

example.h文件:

struct ROW; 
struct CONNECTOR; 

typedef struct { 
    short int Address; 
    short int FirstRegister; 
    short int NumberOfRegisters; 
    short int Sampling; 
}ROW; 

typedef struct { 
    short int NumberOfRows; 
    ROW Rows[200]; 
}CONNECTOR; 

CONNECTOR Connectors[4]; 
+0

'square_array'函數聲明是怎麼樣的? – CristiFati

+0

對不起,我已更新我的問題以包含它。在我們編輯前面的例子時,它被稱爲'square_array'。它不會是最終的名字。 'printf()'語句在訪問特定值時輸出正確的結果。但是,我不確定如何處理完整的返回結構。 –

回答

1

我已經創造了我自己的一個小例子。仔細看看Python代碼後,我可以找出函數頭(並且我還添加了一些虛擬主體)。

問題很簡單,函數返回一個CONNECTOR指針,爲了訪問它的成員,你需要先「解除引用」,否則你會得到AttributeError。這裏是你的代碼(修改一點點):

testlib = ctypes.cdll.LoadLibrary("_example.so") 
testfunc = testlib.square_array 
testfunc.argtype = ctypes.POINTER(CONNECTOR) 
testfunc.restype = ctypes.POINTER(CONNECTOR) 

pconnector0 = testfunc(ctypes.byref(con[0])) 
connector0 = pconnector0.contents 
print(connector0.NumberOfRows) 
print(connector0.Rows[0].Address) 

的「祕密」就在於pconnector0.contents執行的「提領」。

作爲附帶說明的代碼y.Rows[0].Address[0]線將觸發TypeError因爲[0]在端部的:Addressint並且不能被索引(沒有定義__getitem__)。

關於第二種方法(直接調用函數),這是同樣的問題。下面是一些工作代碼:

pconnector1 = testlib.square_array(ctypes.byref(con[0])) 
connector1 = pconnector1.contents 
print(type(connector1)) 

注意:我以前的Python 2.7.10Win10 x64的,但沒有在這裏應該是的Python版本或特定平臺。

+0

非常感謝。我剛剛注意到我正在嘗試索引地址,但我不知道'.contents'。問題是我試圖一次性抓住結構和指針和ctypes,而錯過了取消引用的部分。代碼現在很好用;現在我有一個基礎來整合一些有用的代碼。 –

+0

不客氣! – CristiFati