通过FORTRAN(DLL)返回双数组,以便在python中进一步处理
我已经为这个问题挣扎了一段时间,搜索查询/适用文档也没有产生任何可行的结果;所以把它贴在这里 我想要完成什么:通过FORTRAN(DLL)返回双数组,以便在python中进一步处理,python,dll,fortran,ctypes,fortran77,Python,Dll,Fortran,Ctypes,Fortran77,我已经为这个问题挣扎了一段时间,搜索查询/适用文档也没有产生任何可行的结果;所以把它贴在这里 我想要完成什么: 我有一些用FORTRAN77编写的程序,它接受一些参数并返回一个固定长度的双精度数组 我希望使用另一种编程语言来调用此函数(目前我使用python进行测试;但这可能会发生变化,因此f2py在这里不是一个选项) FORTRAN例程可以概括如下: FUNCTION TST (IIN) IMPLICIT LOGICAL (A-Z) cGCC$ ATTRIBUTES
- 我有一些用FORTRAN77编写的程序,它接受一些参数并返回一个固定长度的双精度数组
- 我希望使用另一种编程语言来调用此函数(目前我使用python进行测试;但这可能会发生变化,因此f2py在这里不是一个选项)
FUNCTION TST (IIN)
IMPLICIT LOGICAL (A-Z)
cGCC$ ATTRIBUTES DLLEXPORT, STDCALL :: TST
INTEGER II,IIN
DOUBLE PRECISION, DIMENSION(3) :: TST
C
C Test function:
DO 1001 II = 1,3
TST(II) = II * 1.11D0 + IIN
1001 CONTINUE
RETURN
END
gfortran -static -c -fdollar-ok -fno-align-commons TEST.for
gfortran -shared -mrtd -static -o TEST.dll TEST.def TEST.o
import ctypes as cs
import numpy as np
#import dll library hooks:
tdll = cs.WinDLL(pathToDLL)
#test:
tdll.TST.restype = None
tdll.TST.argtypes = [cs.POINTER(cs.c_long), cs.POINTER(cs.c_double*3)]
#start testing:
Ar = [0.0, 0.0, 0.0]
_A = np.array(Ar).ctypes.data_as(cs.POINTER(cs.c_double*len(Ar)))
_L = cs.c_long(3)
tdll.TST(cs.byref(_L), _A)
这是使用gcc fortran编译的,如下所示:
FUNCTION TST (IIN)
IMPLICIT LOGICAL (A-Z)
cGCC$ ATTRIBUTES DLLEXPORT, STDCALL :: TST
INTEGER II,IIN
DOUBLE PRECISION, DIMENSION(3) :: TST
C
C Test function:
DO 1001 II = 1,3
TST(II) = II * 1.11D0 + IIN
1001 CONTINUE
RETURN
END
gfortran -static -c -fdollar-ok -fno-align-commons TEST.for
gfortran -shared -mrtd -static -o TEST.dll TEST.def TEST.o
import ctypes as cs
import numpy as np
#import dll library hooks:
tdll = cs.WinDLL(pathToDLL)
#test:
tdll.TST.restype = None
tdll.TST.argtypes = [cs.POINTER(cs.c_long), cs.POINTER(cs.c_double*3)]
#start testing:
Ar = [0.0, 0.0, 0.0]
_A = np.array(Ar).ctypes.data_as(cs.POINTER(cs.c_double*len(Ar)))
_L = cs.c_long(3)
tdll.TST(cs.byref(_L), _A)
其中TEST.def将TST映射到TST_
到目前为止没有问题,但是在python中出现了问题“如何调用此函数并处理返回值?”
使用“depwalker”工具;TST函数显然需要2个参数(TST_u@8)。除了整数之外,我假设这应该是指向输出数组的指针或其长度
我的python代码如下所示:
FUNCTION TST (IIN)
IMPLICIT LOGICAL (A-Z)
cGCC$ ATTRIBUTES DLLEXPORT, STDCALL :: TST
INTEGER II,IIN
DOUBLE PRECISION, DIMENSION(3) :: TST
C
C Test function:
DO 1001 II = 1,3
TST(II) = II * 1.11D0 + IIN
1001 CONTINUE
RETURN
END
gfortran -static -c -fdollar-ok -fno-align-commons TEST.for
gfortran -shared -mrtd -static -o TEST.dll TEST.def TEST.o
import ctypes as cs
import numpy as np
#import dll library hooks:
tdll = cs.WinDLL(pathToDLL)
#test:
tdll.TST.restype = None
tdll.TST.argtypes = [cs.POINTER(cs.c_long), cs.POINTER(cs.c_double*3)]
#start testing:
Ar = [0.0, 0.0, 0.0]
_A = np.array(Ar).ctypes.data_as(cs.POINTER(cs.c_double*len(Ar)))
_L = cs.c_long(3)
tdll.TST(cs.byref(_L), _A)
问题是,这段代码(以及我尝试的任何变体)将生成一个
错误:o错误:异常:访问冲突写入0x0000000F
。如果我试图通过value传递第一个参数,它将导致OSError:exception:access违规读取0x0000000F
有人能给我指一下正确的方向吗 经过一些加工后;此外,还感谢各位提出的宝贵建议,找到了上述问题的解决方案 为了使其正常工作,需要对python方面进行一些细微的更改:
import ctypes as cs
import numpy as np
#import dll library handle:
tdll = cs.WinDLL(pathToDLL)
#specify result and argument types
tdll.TST.restype = None
tdll.TST.argtypes = [cs.POINTER(cs.POINTER(cs.c_double*3)), cs.POINTER(cs.c_long)]
#call the dll function 'TST':
Ar = (cs.c_double*3)()
_A = cs.pointer(Ar)
tdll.TST(cs.byref(_A), cs.byref(cs.c_long(3)))
result = Ar[:]
希望这篇文章能对其他人有所帮助。不要在没有通用标签的情况下使用特定于版本的标签。为什么需要stdcall?您最终计划使用哪种语言?编译后的DLL的某些功能也可在Excel/VBA中使用——最终语言将是C#或python,与VBA结合使用,用于单元测试/通用计算。预期该函数将实现为
void
函数,并带有指向结果的附加参数这正是我的假设,但将数组(或其指针)作为附加参数传递仍然会导致访问冲突