我制作了一个CPP DLL,并试图从python调用其中的函数。 对于其他功能,我已经多次实现了这一目标,但是对于这一点,我只是找不到我的错误。
dll_name = "..\\src\\x64\\Debug\\2019-3A-IBD-MLDLL.dll"
dllabspath = os.path.dirname(os.path.abspath(__file__)) + os.path.sep + dll_name
myDll = CDLL(dllabspath)
#fit_reg_RBF_naive
myDll.fit_reg_RBF_naive.argtypes = [ct.c_void_p, ct.c_double, ct.c_void_p, ct.c_int, ct.c_int]
myDll.fit_reg_RBF_naive.restypes = ct.c_void_p
#predict_reg_RBF_naive
myDll.predict_reg_RBF_naive.argtypes = [ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_int, ct.c_double, ct.c_int]
myDll.predict_reg_RBF_naive.restypes = ct.c_double
def fit_reg_RBF_naive(pyXTrain, pyGamma, pyYTrain, pySampleCount, pyInputCountPerSample):
XTrain = (ct.c_double * len(pyXTrain))(*pyXTrain)
YTrain = (ct.c_double * len(pyYTrain))(*pyYTrain)
inputCountPerSample = ct.c_int(pyInputCountPerSample)
sampleCount = ct.c_int(pySampleCount)
gamma = ct.c_double(pyGamma)
return myDll.fit_reg_RBF_naive(XTrain, gamma, YTrain, sampleCount, inputCountPerSample)
def predict_reg_RBF_naive(pyW, pyXTrain, pyXpredict ,pyInputCountPerSample, pyGamma, pySampleCount):
XTrain = (ct.c_double * len(pyXTrain))(*pyXTrain)
inputCountPerSample = ct.c_int(pyInputCountPerSample)
sampleCount = ct.c_int(pySampleCount)
gamma = ct.c_double(pyGamma)
Xpredict = (ct.c_double * len(pyXpredict))(*pyXpredict)
return myDll.predict_reg_RBF_naive(W, XTrain, Xpredict, inputCountPerSample, gamma, sampleCount)
基本上,我加载DLL,为两个函数设置参数的Ctypes和结果。然后,我制作了一个python包装器,以便用户不必从python到cpp的每次转换都重新输入。
我在cpp端的类型也不错:
extern "C" {
SUPEREXPORT double predict_reg_RBF_naive(double* W, double* X, double* Xpredict, int inputCountPerSample, double gamma, int N);
SUPEREXPORT double* fit_reg_RBF_naive(double* XTrain, double gamma, double* YTrain, int sampleCount, int inputCountPerSample);
}
对于cpp部分,我没有从编译器发出警告,我已经打印了内存地址,然后从cpp返回的fit_reg_RBF_naive
内部和python中的W
都是相同的。>
000002B358384980 // cpp address of W before return
0x58384980 # Python address of W after function call
对我来说,似乎是相同的地址。也许我错了。
所以当我尝试调用第二个cpp函数时,它会说
myDll.predict_reg_RBF_naive(W,XTrain,Xpredict,inputCountPerSample,gamma,sampleCount) OSError:异常:访问冲突读取为0x000000007C7380A0
尝试读取W
时,它在cpp中崩溃了。它们在cpp中不是free
或'delete',并且已正确分配了变量:double* W = new double[2];
另外,当我在Python中打印W
时,我得到<class 'int'>
。
我的W
为何在语言上似乎有相同的地址,但没有好的类型?将fit_reg_RBF_naive
的结果类型更改为POINTER(ct.c_double * 2)
不变。
编辑:
这是我调用函数的方式:
from dll_load import predict_reg_RBF_naive, fit_reg_RBF_naive
gamma = 50
sampleCount = 2
inputCountPerSample = 3
XTrain = [1.0, 1.0, 1.0, 3.0, 3.0, 3.0]
YTrain = [-1.0, 1.0]
Xpredict = [1.0, 1.0, 1.0]
W = fit_reg_RBF_naive(XTrain, gamma, YTrain, sampleCount, inputCountPerSample)
print(predict_reg_RBF_naive(W, XTrain, Xpredict, inputCountPerSample, gamma, sampleCount))
答案 0 :(得分:1)
[Python 3.Docs]: ctypes - A foreign function library for Python。
您拼错了 restype s (应该为 restype )。这样, restype 不会被初始化,并且默认为 int (在 32bit 上这不是问题),并且您遇到了:
除此之外,代码中还有几个问题:
double*
),请不要使用ctypes.c_void_p
(在 argtypes 或 restype )进行映射,因为它可能太宽了,请改用ctypes.POINTER(ctypes.c_double)
(在这种情况下)对我来说,这甚至不编译(我想知道您如何运行该代码)。我将仅在 XTrain 上举例说明,但应用于 YTrain 和 Xpredict 。 ctypes 不知道将 Python 列表转换为ctypes.POINTER(ctypes.c_double)
(或ctypes.c_void_p
),并且转换必须手动进行(转换为ctypes.c_double
数组):
XTrain = [1.0, 1.0, 1.0, 3.0, 3.0, 3.0]
xtrain_ctypes = (ctypes.c_double * len(XTrain))(*XTrain)
并将 xtrain_ctypes 传递给函数。