使用ctypes将python字符串传递给Fortran子例程

时间:2017-02-19 15:10:43

标签: python fortran shared-libraries ctypes

我正在尝试使用ctypes将参数传递给共享库中的Fortran子例程。现在这是我简单的fortran代码:

MODULE test_module
INCLUDES
SUBROUTINE fstr_test(file_or_extension, ierr, iopen)
   IMPLICIT NONE
   INTEGER, INTENT(out) :: ierr
   INTEGER, OPTIONAL :: iopen
   CHARACTER(LEN=*), INTENT(in) :: file_or_extension
   WRITE(6,*) file_or_extension,ierr,iopen
   RETURN
END SUBROUTINE fstr_test
END MODULE test_module

我用

编译它
gcc -shared -fPIC -o libtest.o fstr_test.f90

这似乎工作正常,我实际上可以在Python 3中加载共享库。这里是非崩溃的代码:

from ctypes import *
libtest = cdll.LoadLibrary("libtest.so")
f = libtest.test_module_MOD__fstr_test
file = b'wout_li383.nc'
ierr = c_int(0)
iopen = c_int(0)
cfile=c_char_p(b"test_str")
f(cfile,byref(ierr),byref(iopen))

但是,我似乎无法正确传递字符串。在上面的表单中,字符串为空,两个整数正确打印到控制台。基本上我所取得的唯一进步就是让Python崩溃。我在这里尝试了解决方案:

Passing string to Fortran DLL using ctypes and Python

但它似乎对我不起作用,也许是因为它在谈论Python 2?

例如

f.argtype = [c_char_p,c_int_c_int]
c = c_char_p(b"test.txt")
f(c,byref(ierr),byref(iopen))

不会崩溃内核但字符串为空。更改为byref:

f.argtype = [c_char_p,c_int_c_int]
c = c_char_p(b"test.txt")
f(byref(c),byref(ierr),byref(iopen))

效果相同。现在,如果我尝试通过添加长度参数传递长度并传递它,我得到一个“死内核”的消息,我必须重新启动内核。本身没有错误消息。

f.argtype = [c_char_p,c_int,c_int_c_int]
file = b'text.txt'
c = c_char_p(file)
c_len = c_int(len(file))
f(c,byref(c_len),byref(ierr),byref(iopen))

希望这澄清一下。我没有收到错误消息,内核正在死亡。

1 个答案:

答案 0 :(得分:3)

所以一些问题,一个隐藏的长度(至少与gfortran未知的其他编译器所做的事情)应该放在参数列表的末尾。你也不需要它上面的byref,也不要在c_char_p中包装字节串

更改子程序中的ierr变量

  SUBROUTINE fstr_test(file_or_extension, ierr, iopen)
     IMPLICIT NONE
     INTEGER, INTENT(out) :: ierr
     INTEGER, OPTIONAL :: iopen
     CHARACTER(LEN=*), INTENT(in) :: file_or_extension
     WRITE(6,*) file_or_extension,ierr,iopen
     ierr=1
     RETURN
  END SUBROUTINE fstr_test

gfortran -shared -fPIC -o libtest.so fstr_test.f90

然后python代码应为:

import ctypes

lib=ctypes.CDLL("./libtest.so")
f=getattr(lib,'__test_module_MOD_fstr_test')

f.argtypes=[ctypes.c_char_p,ctypes.c_int,ctypes.c_int,ctypes.c_int]
f.restype=None

x=b'abcdef'
ierr=ctypes.c_int(0)
iopen=0
f(x,ctypes.byref(ierr),iopen,len(x))
print(ierr.value)

虽然我还没有让可选参数工作,但是我已经添加了一个空int,这应该会将字符串传入并获得更多。