我正在尝试使用ctypes模块从python程序中调用我编写的线性代数例程(fortran)库。我已经成功导入了库,可以调用我的子例程和返回单个值的函数。我的问题是调用返回双精度数组的函数。我无法弄清楚如何指定返回类型。结果,每当我调用这样的函数时,我都会遇到段错误。
这是一个最小的工作示例,一个在两个3向量之间取得交叉乘积的例程:
!****************************************************************************************
! Given vectors a and b, c = a x b
function cross_product(a,b)
real(dp) a(3), b(3), cross_product(3)
cross_product = (/a(2)*b(3) - a(3)*b(2), &
a(3)*b(1) - a(1)*b(3), &
a(1)*b(2) - a(2)*b(1)/)
end function cross_product
这是我的python脚本:
#!/usr/bin/python
from ctypes import byref, cdll, c_double
testlib = cdll.LoadLibrary('/Users/hart/codes/celib/trunk/libutils.so')
cross = testlib.vector_matrix_utilities_mp_cross_product_
a = (c_double * 3)()
b = (c_double * 3)()
a[0] = c_double(0.0)
a[1] = c_double(1.0)
a[2] = c_double(2.0)
b[0] = c_double(1.0)
b[1] = c_double(3.0)
b[2] = c_double(2.0)
print a,b
cross.restype = c_double * 3
print cross.restype
print cross(byref(a),byref(b))
这是输出:
goku:~/python/ctypes> ./test_example.py
<__main__.c_double_Array_3 object at 0x10399b710> <__main__.c_double_Array_3 object at 0x10399b7a0>
<class '__main__.c_double_Array_3'>
Segmentation fault: 11
goku:~/python/ctypes>
我尝试了“cross.restype = ...”这一行的不同排列,但我无法弄清楚实际应该去哪里。感谢您阅读此问题。 --Gus
答案 0 :(得分:1)
编译器可能会返回指向数组或数组描述符的指针......因此,在混合语言时,除了包装器专门支持Fortran之外,应始终使用bind(C)
。并且(毫不奇怪)bind(C)
函数不能返回数组。理论上你可以分配数组并将type(c_ptr)
返回给它,但是在使用之后如何处理它呢?
所以我的建议是使用子程序。
答案 1 :(得分:0)
使用gfortran函数调用有一个隐藏的参数:
>>> from ctypes import *
>>> testlib = CDLL('./libutils.so')
>>> cross = testlib.cross_product_
>>> a = (c_double * 3)(*[0.0, 1.0, 2.0])
>>> b = (c_double * 3)(*[1.0, 3.0, 2.0])
>>> c = (c_double * 3)()
>>> pc = pointer(c)
>>> cross(byref(pc), a, b)
3
>>> c[:]
[-4.0, 2.0, -1.0]
但Vladimir's suggestion使用bind(C)
和子程序是更好的方法。
仅供参考,数组成为C函数调用的指针,因此使用byref
是多余的。我需要byref
和pointer
才能为隐藏参数创建double **
。