使用Ctypes时与Fortran DLL的访问冲突
我正在尝试让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))
这是Fortran 90代码:
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本身就是一个指针,所以不需要再用指针。
1 个回答
4
我不太清楚你使用的Fortran编译器的具体规则,所以我会给出一些一般性的建议,而不是具体的细节:
- 你的调用约定不一致。Fortran代码使用的是stdcall,而ctypes代码使用的是cdecl。你需要让它们一致。例如,可以把ctypes改成用
windll
,而不是cdll
。 - 你确定
POINTER(c_char_p)
是对的吗?这个是指向指向以空字符结尾的字符串的指针。我觉得你可能在Python那边多了一层指针,但我不能百分之百确定。 - @eryksun在评论中提到,隐式字符串长度参数是按值传递的,而不是按引用传递的。
除此之外,我看不出有什么问题,虽然我对Fortran一无所知,所以不能保证这些。
如果我是你,我会先把代码简化到一个只传递一个整数参数的简单函数。然后再添加一个整数数组,检查一下你能否在这种参数下双向传输数据。接着再尝试字符串。不要一开始就尝试这么复杂的参数列表,因为那样会给自己带来很多潜在的问题,而且很难知道从哪里入手。