You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python的ctypes调用Fortran DLL中的变量数据

解决Python ctypes调用Fortran动态库无法获取模块变量的问题

核心问题

你遇到的问题本质是:ctypes默认会把动态库中的同名符号解析为函数指针(_FuncPtr),但nm -D显示的__zd1_MOD_density(类型B,bss段未初始化全局变量)和__zd1_MOD_species_name(类型D,data段已初始化全局变量)是数据符号,并非函数,直接访问会导致类型不匹配,触发AttributeError。

解决步骤

1. 正确获取数据符号

不要通过库对象直接访问变量,使用ctypes.CDLL的in_dll方法,明确指定符号名和对应的数据类型。

2. 针对不同变量类型的代码示例

假设你的Fortran代码中:

  • density是一维双精度数组(real(8), dimension(5) :: density)
  • species_name是长度为20的字符串(character(len=20) :: species_name)

Python代码如下:

import ctypes

# 加载动态库
zd_lib = ctypes.CDLL('./zd.so')

# 先执行Fortran子程序,确保变量已被赋值
zd_lib.__zd1_MOD_zd()

# 读取density数组
# 定义对应数组类型:5个double元素
DensityArray = ctypes.c_double * 5
density = DensityArray.in_dll(zd_lib, '__zd1_MOD_density')
# 遍历输出数组值
print("Density:", [val for val in density])

# 读取species_name字符串
# Fortran字符串在gfortran中是「4字节长度前缀 + 字符数据」的结构
class FortranString(ctypes.Structure):
    _fields_ = [("len", ctypes.c_int), ("chars", ctypes.c_char * 20)]

species_name = FortranString.in_dll(zd_lib, '__zd1_MOD_species_name')
# 解码并去除末尾空字符
print("Species Name:", species_name.chars.decode('utf-8').rstrip('\x00'))

3. 关键注意事项

  • 类型严格匹配:
    • Fortran的real(4)对应ctypes.c_float,real(8)对应ctypes.c_double
    • 二维数组需用嵌套类型,比如(ctypes.c_double * 5) * 3对应real(8), dimension(3,5)
  • 字符串结构适配:不同Fortran编译器的字符串内存布局可能有差异,gfortran默认用4字节长度前缀,若使用其他编译器需调整结构定义
  • 编译选项确保可见性:编译动态库时必须加-fPIC(位置无关代码),命令示例:
    gfortran -shared -fPIC zd.f90 -o zd.so
    

4. 验证符号类型

若不确定符号属性,可执行以下命令确认:

objdump -tT zd.so | grep __zd1_MOD_

输出中D/B标识数据符号,T标识函数符号。

内容的提问来源于stack exchange,提问作者YOU

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 11:40:41