如何通过ctypes向Fortran模块传递字符串数组并实现Fortran端读取
Python通过ctypes传递字符串数组到Fortran模块的实现方案
问题背景
通过Python的ctypes将字符串数组传递给Fortran模块,已有的Python代码如下:
import ctypes as ct files = [b"FILE1.RSX", b"FILE2.RSX"] file_ptrs = (ct.c_char_p * len(files))(*files) lib2 = ct.CDLL('./reader.so') lib2.read_data.argtypes = [ct.POINTER(ct.c_char_p)] lib2.read_data(file_ptrs)
需要修改Fortran子程序框架,实现对该字符串数组的读取,原Fortran框架存在参数缺失和类型声明问题:
subroutine read_rsx(files) bind(c, name="read_data") use iso_c_binding IMPLICIT DOUBLE PRECISION (A-H,O-Z) integer(c_int), value :: numFile type(c_ptr), intent(in) :: files(numFile) ... end subroutine read_data
解决步骤及代码实现
1. 调整Python代码:传递数组长度
C风格的指针数组不包含长度信息,Fortran无法自动获取数组元素个数,因此需要额外传递数组长度参数:
import ctypes as ct files = [b"FILE1.RSX", b"FILE2.RSX"] file_count = len(files) # 创建C风格的字符指针数组 file_ptrs = (ct.c_char_p * file_count)(*files) lib2 = ct.CDLL('./reader.so') # 更新函数参数类型声明,添加整数类型的长度参数 lib2.read_data.argtypes = [ct.c_int, ct.POINTER(ct.c_char_p)] # 传递长度和指针数组 lib2.read_data(file_count, file_ptrs)
2. 修正Fortran子程序:读取字符串数组
修改Fortran代码,解决类型冲突问题,并实现C字符串到Fortran字符串的转换:
subroutine read_data(num_file, files) bind(c, name="read_data") use iso_c_binding implicit none ! 替代旧的隐式声明,避免类型混淆 integer(c_int), intent(in), value :: num_file ! 接收数组长度 type(c_ptr), intent(in) :: files(num_file) ! C风格的字符指针数组 character(kind=c_char), pointer :: c_str(:) ! 用于指向C字符串的指针 character(len=:), allocatable :: fortran_str ! 转换后的Fortran字符串 integer :: i, str_len ! 遍历每个字符串指针 do i = 1, num_file ! 将C指针绑定到Fortran字符数组 call c_f_pointer(files(i), c_str, [1]) ! 计算C字符串的实际长度(直到遇到终止符\0) str_len = 0 do while(c_str(str_len+1) /= c_null_char) str_len = str_len + 1 end do ! 分配对应长度的Fortran字符串并复制内容 allocate(character(len=str_len) :: fortran_str) fortran_str = transfer(c_str(1:str_len), fortran_str) ! 这里可以添加自定义处理逻辑,比如打印字符串 print *, "第", i, "个文件:", trim(fortran_str) ! 释放临时资源 deallocate(fortran_str) nullify(c_str) end do end subroutine read_data
3. 编译Fortran代码
使用gfortran编译为共享库:
gfortran -shared -fPIC -o reader.so your_fortran_file.f90
关键说明
- 隐式声明问题:原代码中的
IMPLICIT DOUBLE PRECISION会导致c_int等C绑定类型被错误隐式声明为双精度,改用implicit none可以避免这类问题。 - 字符串转换:C字符串以
\0作为终止符,需要手动遍历获取长度,再通过transfer函数转换为Fortran风格的字符串。 - 数组长度传递:必须显式传递数组长度,否则Fortran无法确定指针数组的元素个数。
内容的提问来源于stack exchange,提问作者Michael Leanza
相关产品推荐
相关产品推荐

