【问题标题】:Access violation with Ctypes Python <> Fortran DLL与 Ctypes Python <> Fortran DLL 的访问冲突
【发布时间】:2012-01-05 17:29:59
【问题描述】:

我正在尝试让 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,并删除了双 POINTER 和 byref() 用法。另外,c_char_p 已经是一个指针,所以它不需要一个 POINTER。

【问题讨论】:

  • 你知道,你的编译器不会向你收取更多的费用来编译更长的变量名。只是说...
  • @Stefano Fortran 是别人的代码,编写了非常短名称的悠久传统。在边界的另一边使用相同的名称是有意义的。
  • @David Heffernan:原来的名字太短了,你可以用它们作为前缀。
  • 您在对问题的编辑中指出问题是字符串长度传递。那真的是唯一的错误吗?此外,您不应该将您的问题更新为“已解决”。您应该接受一个存在可接受的答案,或者添加您自己的答案并接受它。本网站旨在采用问答格式。
  • 抱歉,我找不到将 cmets 标记为答案的方法,所以我先进行了编辑..

标签: python dll fortran ctypes


【解决方案1】:

我不确定你的 Fortran 编译器的约定是什么,所以我会回答一些一般性的观点而不是具体的:

  1. 您的调用约定不匹配。 Fortran 代码指定stdcall,ctypes 代码指定cdecl。你需要让它们匹配。例如,将 ctypes 更改为使用 windll 而不是 cdll。
  2. 你确定POINTER(c_char_p) 是对的吗?那是一个指向以空字符结尾的字符串的指针。我认为您可能在 Python 端有一个额外的间接层,但我不能 100% 确定这一点。
  3. @eryksun 在评论中指出隐式字符串长度参数是按值而不是按引用传递的。

否则我看不出有什么问题,虽然我对 Fortran 一无所知,所以我不能保证。

如果我是你,我会直接将其简化为传递单个 int 参数的普通函数。然后我将添加一个 int 数组并检查您是否可以为此类参数双向传输数据。然后向上移动到一个字符串。不要从头开始尝试如此复杂的参数列表,因为你给自己带来了太多潜在的陷阱,而且很难知道从哪里开始。

【讨论】:

  • 这不是我的 DLL,所以很遗憾,没有更简单的函数可以使用:\ 我将尝试使用 windll! POINTER() 只是我尝试使其工作的方法之一,因为我看到了一些成功的论坛帖子。
  • 没有问题。使用适当简单的函数编写您自己的 fortran DLL。同时修复调用约定,看看是否有帮助。
  • @user1064136:字符串的长度是按值传递的,而不是按引用传递的。
猜你喜欢
  • 1970-01-01
  • 2012-05-02
  • 1970-01-01
  • 1970-01-01
  • 2013-03-06
  • 1970-01-01
  • 1970-01-01
  • 2019-06-19
  • 1970-01-01
相关资源
最近更新 更多