使用 ctypes 将 python 字符串传递给 Fortran 子例程
Passing python strings to Fortran subroutine using 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))
同样的效果。现在,如果我尝试通过添加长度参数并传递它来传递长度,我会收到 "Dead Kernel" 的消息,并且我必须重新启动内核。本身没有错误消息。
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))
希望这能说明问题。我没有收到错误消息,内核快死了。
所以有几个问题,一个隐藏长度(至少 gfortran 不知道其他编译器做什么)应该放在参数列表的末尾。您也不需要 byref,也不要将 byte-string 包装在 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,这应该是你传入字符串并输出 ierr。
我正在尝试使用 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))
同样的效果。现在,如果我尝试通过添加长度参数并传递它来传递长度,我会收到 "Dead Kernel" 的消息,并且我必须重新启动内核。本身没有错误消息。
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))
希望这能说明问题。我没有收到错误消息,内核快死了。
所以有几个问题,一个隐藏长度(至少 gfortran 不知道其他编译器做什么)应该放在参数列表的末尾。您也不需要 byref,也不要将 byte-string 包装在 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,这应该是你传入字符串并输出 ierr。