如何通过Python从Fortran DLL获取数据?解决ctypes.cast执行异常问题
问题根源
你这段代码的核心问题是Fortran函数返回了局部变量的内存地址:函数里的y是栈上的局部自动变量,当FortAddr执行完毕返回后,栈上的y会被销毁,对应的内存空间会被系统回收或重新分配。此时Python拿到的地址是无效的,调用ctypes.cast访问这块内存必然会导致程序崩溃或未定义行为。
正确解决方案
根据你的需求(获取Fortran计算的数据用于Python可视化),有两种常用的正确实现方式:
方式一:直接返回计算结果(适合单个值)
不需要传递内存地址,直接让Fortran函数返回计算后的数值,这是最简单安全的方式。
修改后的Fortran代码
integer(c_int) function FortCalc(x) bind(c, name="FORTCALC") !DEC$ ATTRIBUTES DLLEXPORT::FortCalc use, intrinsic :: iso_c_binding integer(kind=c_int), intent(in) :: x integer :: y y = 2 * x FortCalc = int(y, c_int) ! 显式转换为C兼容的int类型 end function
对应的Python调用代码
import ctypes flib = ctypes.CDLL('FortDll.dll') # 显式声明函数返回类型,避免ctypes默认推断的潜在问题 flib.FORTCALC.restype = ctypes.c_int x = ctypes.c_int(15) result = flib.FORTCALC(x) print(result) # 输出30,可直接用于可视化
方式二:通过内存缓冲区传递数据(适合数组/大数据)
如果需要传递大量数据(比如用于可视化的数组),可以让Python预先分配内存缓冲区,Fortran直接写入这块内存,避免内存所有权问题。
Fortran代码(填充数组)
subroutine FortFillArray(arr, length) bind(c, name="FORTFILLARRAY") !DEC$ ATTRIBUTES DLLEXPORT::FortFillArray use, intrinsic :: iso_c_binding integer(kind=c_int), intent(out) :: arr(*) integer(kind=c_int), intent(in) :: length integer :: i do i = 1, length arr(i) = 2 * i ! 示例:生成2倍的序列值 end do end subroutine
Python调用代码
import ctypes flib = ctypes.CDLL('FortDll.dll') # 显式声明函数参数类型和返回类型 flib.FORTFILLARRAY.argtypes = [ctypes.POINTER(ctypes.c_int), ctypes.c_int] flib.FORTFILLARRAY.restype = None # 定义数组长度并分配内存 data_length = 10 arr_buffer = (ctypes.c_int * data_length)() # 调用Fortran子程序填充数组 flib.FORTFILLARRAY(arr_buffer, data_length) # 转换为Python列表,方便后续可视化 py_data = [val for val in arr_buffer] print(py_data) # 输出[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
内容的提问来源于stack exchange,提问作者elquin
相关产品推荐
相关产品推荐

