【问题标题】:Return double array through FORTRAN (DLL) to process further in python通过 FORTRAN(DLL)返回双精度数组以在 python 中进一步处理
【发布时间】:2014-12-26 10:35:27
【问题描述】:

我已经为这个问题苦苦挣扎了一段时间,搜索查询/适用文档也没有产生任何可行的结果;因此将其发布在这里。

我想完成什么:

  • 我有一些用 FORTRAN77 编写的程序,它接受一些参数并返回一个固定长度的双精度数组。
  • 我希望使用另一种编程语言来调用此函数(目前我使用 python 进行测试;但这可能会发生变化 - 所以这里 f2py 不是一个选项)

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

这是用gcc-fortran编译如下:

gfortran -static -c -fdollar-ok -fno-align-commons TEST.for
gfortran -shared -mrtd -static -o TEST.dll TEST.def TEST.o

TEST.defTST 映射到 tst_

到目前为止没有问题,但是在 python 中出现了问题“我如何调用这个函数并处理返回值?”

使用“depwalker”工具; TST 函数显然需要 2 个参数 (tst_@8)。除了一个整数,我认为这应该是一个指向输出数组的指针或其长度。

我的python代码如下:

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)

问题是这段代码(连同我尝试的任何变体)将产生一个 错误:OSError: exception: access violation writing 0x0000000F。如果我尝试通过第一个参数 ByValue,它将导致 OSError: exception: access violation reading 0x0000000F

有人可以在这里指出正确的方向吗?

【问题讨论】:

  • 不要使用没有通用标签的版本特定标签。
  • 为什么需要stdcall?您的最终计划是哪种语言?
  • 已编译 DLL 的某些功能也可用于 Excel/VBA——最终语言将是 C# 或 python 结合 VBA 用于单元测试/通用计算
  • 期望函数被实现为 void 函数,带有一个带有指向结果数组的指针的附加参数。
  • 这正是我的假设,但是将数组(或其指针)作为附加参数传递仍然会导致访问冲突

标签: python dll fortran ctypes fortran77


【解决方案1】:

经过一些工具处理后;也感谢Vladimir F的宝贵建议,已经找到了上述问题的解决方案。

为了使其正常工作,需要在 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[:]

希望这篇文章可能对其他人有所帮助。

【讨论】:

    猜你喜欢
    • 2019-11-14
    • 2017-01-06
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 2010-12-04
    • 2014-04-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多