我试图让 Python 使用 Fortran DLL(通过引用调用)。运行 Fortran 90 代码时,它运行良好,但在 Python 中无法运行;它只会给出“访问冲突”错误或“没有足够的参数调用”。
python 代码:
from ctypes import *
mydll = cdll.LoadLibrary("test.dll")
# This function works.
print mydll.XIT() # prints 0
mydll.GetInfo.argtypes = [POINTER(c_int),POINTER(c_int),POINTER(c_int),POINTER(c_int),POINTER(c_int),POINTER(c_int),POINTER(c_char_p)]
rm = c_int()
rf = c_int()
vm = (c_int * 5)()
vf = (c_int * 5)()
np = c_int(14)
p = (c_int * 14)()
filename = "test"
fn = c_char_p(filename)
nc = c_int(len(filename)) # length of string. (Hidden argument in Fortran)
# throws insufucient arguments
print mydll.GetInfo(rm,rf,vm,vf,np,p,fn,nc)
# throws access violation
print mydll.GetInfo(byref(rm),byref(rf),byref(vm),byref(vf),byref(np),byref(p),byref(fn),byref(nc))
fortran90代码:
program test
implicit none
integer, parameter :: np = 14
integer :: rm, rf
integer, dimension(5) :: vm, vf
integer, dimension(np) :: p
character(len=80) :: fn
interface
integer function GetInfo(rm, rf, vm, vf, np, p, fn)
!dec$ attributes dllimport, stdcall, reference, decorate, alias:'GetInfo' :: GetInfo
implicit none
character(len=*), intent(in) :: fn
integer, intent(in) :: np
integer, intent(out) :: rm,rf
integer, intent(out), dimension(5) :: vm,vf
integer, intent(out), dimension(np) :: p
end function GetInfo
end interface
fn = "test"
print *, GetInfo(rm, rf, vm, vf, np, p, fn)
end program test
编辑: 我修改了我的代码,现在不传递字符串长度作为引用。我已将 cdll 切换为 windll,并删除了双指针和 byref() 用法。此外,c_char_p 已经是一个指针,因此它不需要指针。
最佳答案
我不确定您的 Fortran 编译器的约定是什么,所以我将回答一些一般性问题而不是具体问题:
- 您的调用约定不匹配。 Fortran 代码指定 stdcall,ctypes 代码指定 cdecl。您需要使它们匹配。例如,将 ctypes 更改为使用
windll
而不是cdll
。 - 你确定
POINTER(c_char_p)
是正确的吗?这是一个指向以空字符结尾的字符串的指针。我认为您可能在 Python 端有一个额外的间接层,但我对此不是 100% 确定。 - @eryksun 在评论中指出,隐式字符串长度参数是按值而不是按引用传递的。
否则我看不出有什么不对,虽然我对 Fortran 一无所知,所以我不能保证这一点。
如果我是你,我会把它缩减为一个传递单个 int 参数的普通函数。然后我将添加一个 int 数组并检查您是否可以为此类参数双向传输数据。然后向上移动到一个字符串。不要从头开始尝试如此复杂的参数列表,因为这样会给自己带来太多潜在的陷阱,而且很难知道先从哪里看。
关于python - Ctypes Python <> Fortran DLL 的访问冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8258861/