2016-08-25 73 views
-5

我這樣做,但得到錯誤。python傳遞struct和指向c函數的輸入輸出

使用ctypes有什麼錯誤,或者我通過的參數類型有問題嗎?

我覺得有可能是三點應該思考:

  1. 生成傳遞給c函數在Python正確的參數。

  2. 將結構類型的指針傳遞給c函數。

  3. 右實例化結構取決於給定的數組,如果需要python代碼中的結構。

我是c的新手,尤其是指針。

C代碼:結構,ansfer.h

typedef unsigned char boolean_T; 


struct emxArray_real_T 
{ 


    double *data; 
    int *size; 
    int allocatedSize; 
    int numDimensions; 
    boolean_T canFreeData; 
}; 

由蟒調用的函數,ansfer.c

void ansferA(const emxArray_real_T *dataArray, double H, emxArray_real_T *TE, 
       emxArray_real_T *Lag) 
{ 

... 

P2 += dataArray->data[a + dataArray->size[0] * b]; 

... 

TE->data[a + TE->size[0] * b] = te; 

Lag->data[a + Lag->size[0] * b] = h; 

... 
} 

然後,將生成gcc -o libansfer.so -shared -fPIC *.c

libansfer.so。

我根據建議重寫了test.py。添加結構如下。

Python代碼:test.py

import numpy as np 
import ctypes 

c_double_p = ctypes.POINTER(ctypes.c_double) 
c_int_p = ctypes.POINTER(ctypes.c_int) 

class emxArray_real_T(ctypes.Structure): 
    _fields_ = [ 
     ("data",   c_double_p), 
     ("size",   c_int_p), 
     ("allocatedSize", ctypes.c_int), 
     ("numDimensions", ctypes.c_int), 
     ("canFreeData", ctypes.c_bool) 
    ] 

indata = np.array([[1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1],[2.2,2.2,2.2,2.2,2.2,2.2,2.2,2.2,2.2,2.2,2.2,2.2,2.2,2.2,2.2,2.2],[3.3,3.3,3.3,3.3,3.3,3.3,3.3,3.3,3.3,3.3,3.3,3.3,3.3,2.2,2.2,2.2]]) 

LL, CC = indata.shape 

TE = np.zeros((LL,LL), dtype=np.double) 
Lag = np.zeros((LL,LL), dtype=np.double) 

SS = np.array([LL, CC]) 
instruct = emxArray_real_T() 
instruct.data = c_double_p(ctypes.c_double(indata.ctypes.data)) 
instruct.size = c_int_p(ctypes.c_int(SS.ctypes.data)) 
instruct.allocatedSize = ctypes.c_int(LL*CC) 
instruct.numDimensions = ctypes.c_int(2) 
instruct.canFreeData = ctypes.c_bool(0) 

ss = np.array([LL, LL]) 
outstruct1 = emxArray_real_T() 
outstruct1.data = c_double_p(ctypes.c_double(TE.ctypes.data)) 
outstruct1.size = c_int_p(ctypes.c_int(ss.ctypes.data)) 
outstruct1.allocatedSize = ctypes.c_int(LL*LL) 
outstruct1.numDimensions = ctypes.c_int(2) 
outstruct1.canFreeData = ctypes.c_bool(0) 

outstruct2 = emxArray_real_T() 
outstruct2.data = c_double_p(ctypes.c_double(Lag.ctypes.data)) 
outstruct2.size = c_int_p(ctypes.c_int(ss.ctypes.data)) 
outstruct2.allocatedSize = ctypes.c_int(LL*LL) 
outstruct2.numDimensions = ctypes.c_int(2) 
outstruct2.canFreeData = ctypes.c_bool(0) 

lib = ctypes.cdll.LoadLibrary('./libansfer.so') 

lib.ansferA(instruct,ctypes.c_double(3), outstruct1, outstruct2) 

但類似的錯誤

Traceback (most recent call last): 
    File "C:\Python27\testfile\test.py", line 106, in <module> 
    lib.ansferA(instruct,ctypes.c_double(3), outstruct1, outstruct2) 
WindowsError: exception: access violation writing 0x0000000000000000 
+3

顯示的代碼既不可讀又不完整。請抽出時間來證明閱讀,並正確地設置你的問題並提供[mcve]。 – kaylum

+1

C似乎需要指向'struct emxArray_real_T'的指針作爲最右邊的兩個參數,但是您將指針傳遞給雙精度。您需要將結構描述爲ctypes。它試圖訪問其中一個指針成員時可能會崩潰。 – cdarke

+0

'byref(ctypes.c_double(indata.ctypes。數據))'將數據'(「一個指向數組內存區域的指針作爲Python整數」),然後將其轉換爲'double'(不是雙精度指針!),然後將指針指向該double。 'indata.ctypes.data_as(ctypes.POINTER(ctypes.c_double))'會代之以代替,但看看cdarke寫關於結構體的東西。 – DavidW

回答

0

這不是一個答案,但格式規則不允許我把這個作爲一個評論(仍然可讀)。

的結構會是這個樣子:

c_double_p = ctypes.POINTER(ctypes.c_double) 
c_int_p = ctypes.POINTER(ctypes.c_int) 

class emxArray_real_T(ctypes.Structure): 
    _fields_ = [ 
     ("data",   c_double_p), 
     ("size",   c_int_p), 
     ("allocatedSize", ctypes.c_int), 
     ("numDimensions", ctypes.c_int), 
     ("canFreeData", ctypes.c_bool) 
    ] 

我擁有的canFreeData類型猜測,boolean_T是不是一個標準的C型。

然後用像初始化結構:

emxArray_struct = emxArray_real_T(insert values here as parameters) 

我還沒有和numpy的工作,所以如果/如何的類型映射到ctypes的或常規的Python變量類型,我不知道。

+0

非常感謝。 – glen