Нарушение прав доступа с помощью Ctypes Python <> Fortran DLL - PullRequest
3 голосов
/ 24 ноября 2011

Я пытаюсь заставить 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 уже является указателем, поэтому ему не нужен указатель.

1 Ответ

4 голосов
/ 24 ноября 2011

Я не уверен в том, каковы соглашения вашего компилятора Фортрана, поэтому я отвечу с некоторыми общими моментами, а не с особенностями:

  1. Ваши соглашения о вызовах не совпадают.Код Fortran указывает stdcall, а код ctypes - cdecl.Вы должны заставить их совпадать.Например, измените ctypes для использования windll вместо cdll.
  2. Вы уверены, что POINTER(c_char_p) правильно?Это указатель на указатель на завершенную нулем строку.Я думаю, у вас, вероятно, есть дополнительный уровень косвенности в конце Python, но я не уверен на 100% в этом.
  3. @ eryksun заявляет в комментарии, что неявный параметр длины строки передается по значению, а не по значениюпо ссылке.

В противном случае я не вижу ничего плохого, хотя я ничего не знаю о Фортране, поэтому я не могу ручаться за это.

На вашем месте я бы порезалсяэто прямо к тривиальной функции, которая передает один параметр int.Затем я бы добавил массив int и проверил, что вы можете передавать данные в обоих направлениях для такого параметра.Затем перейдите к строке.Не пытайтесь создать такой сложный список параметров с нуля, потому что вы просто получаете слишком много потенциальных ловушек, и трудно понять, где искать в первую очередь.

...