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

如何用Python ctypes调用Fortran编译的共享库?

Python ctypes调用Fortran共享库的类型匹配问题

我没有Fortran编程经验,尝试用Python ctypes调用Fortran编译的共享库。已经用命令gfortran -shared -g -o test.so test.f90将test.f90编译为test.so共享库。

查阅资料后知道要匹配对应数据类型(比如用ctypes.c_double(123)对应Fortran的real(kind=c_double)),但还是出现Type Error: wrong type错误。对于real(kind=c_double),dimension(*)类型的数组参数,我尝试用np.array([[1,2],[3,4]]).ctypes.data_as(POINTER(c_double))传递,又出现新错误:TypeError: item 2 in _argtypes_ has no from_param method。

附上Fortran代码与Python代码,不确定函数需要传递的正确数据类型,求解答。

Fortran代码(test.f90)

function sticksum( anzd, w, b, a, weight, val, maxTchan, sthresh) result(spek) bind(c, name="sticksum")
    use, intrinsic :: iso_c_binding

    real(kind=c_double) :: anzd
    real(kind=c_double) :: b,a
    real(kind=c_double),dimension(*) :: w,weight
    real(kind=c_double),dimension(*) :: val
    integer(kind=c_int) :: maxTchan
    real(kind=c_double) :: sthresh
    real(kind=c_double) :: spek

    integer :: i, t, j,anz
    real    :: stick, maxw
    
    
    anz = anzd
    spek = 123
    i=1
    t = w(i) * b + a + 1.5
    if(t >= 1) THEN
        spek = anz
        stick = 0. + val(t)
        maxw = weight(i)*stick
        do i=2,anz
            t = w(i) * b + a + 1.5
            if(t > maxTchan) exit
            stick = val(t)
            maxw = max(weight(i)*stick,maxw)
            if( (w(i)*w(i)-w(i-1)*w(i-1)) > 0.5) THEN
                spek = spek + maxw
                maxw = 0
            end if
        end do
    end if
end function sticksum

原Python代码

from ctypes import *
import numpy as np 
so_file = "./test.so"
my_functions = CDLL(so_file)

print(type(my_functions))

my_functions.sticksum_4.argtypes = [c_double,np.ndarray.ctypes,c_double,c_double,np.ndarray.ctypes,np.ndarray.ctypes,c_int, c_double]
my_functions.restype = c_double

anzd = c_double(123) 
w = np.array([[1,2],[3,4]]).ctypes.data_as(POINTER(c_double))
b=c_double(123) 
a=c_double(123) 
weight=np.array([[1,2],[3,4]]).ctypes.data_as(POINTER(c_double))
val=np.array([[1,2],[3,4]]).ctypes.data_as(POINTER(c_double))
maxTchan=c_int(123)
sthresh=c_double(123)


sum = my_functions.sticksum_4(anzd,w,b,a,weight,val,maxTchan,sthresh)

问题修正与解释

1. 函数名错误

Fortran代码中通过bind(c, name="sticksum")指定了C兼容的函数名为sticksum,Python中不需要加_4后缀,直接使用my_functions.sticksum即可。

2. argtypes类型错误

np.ndarray.ctypes不是有效的ctypes类型,Fortran的dimension(*)数组对应C的指针类型,所以argtypes里的数组参数应该用POINTER(c_double)。

3. 数组类型与内存布局

确保numpy数组是np.float64类型(对应c_double),可以在创建数组时指定dtype=np.float64;另外Fortran默认是列优先存储,如果你需要传递多维数组给Fortran处理,最好用np.asfortranarray()转换内存布局,不过这里Fortran用dimension(*)按一维处理,所以直接转指针也能工作,但显式指定类型更稳妥。

修正后的Python代码

from ctypes import *
import numpy as np 

so_file = "./test.so"
my_functions = CDLL(so_file)

# 正确设置函数参数类型与返回值类型
my_functions.sticksum.argtypes = [
    c_double,          # anzd
    POINTER(c_double), # w
    c_double,          # b
    c_double,          # a
    POINTER(c_double), # weight
    POINTER(c_double), # val
    c_int,             # maxTchan
    c_double           # sthresh
]
my_functions.sticksum.restype = c_double

# 准备参数,确保数组为float64类型
anzd = c_double(123)
# 创建float64类型的数组,转成c_double指针
w = np.array([[1,2],[3,4]], dtype=np.float64).ctypes.data_as(POINTER(c_double))
b = c_double(123)
a = c_double(123)
weight = np.array([[1,2],[3,4]], dtype=np.float64).ctypes.data_as(POINTER(c_double))
val = np.array([[1,2],[3,4]], dtype=np.float64).ctypes.data_as(POINTER(c_double))
maxTchan = c_int(123)
sthresh = c_double(123)

# 调用函数
sum_result = my_functions.sticksum(anzd, w, b, a, weight, val, maxTchan, sthresh)
print(sum_result)

额外注意点

  • Fortran中anz = anzd是把双精度数转成整数,如果anzd不是整数可能会截断,这里要注意逻辑是否符合预期。
  • 传递数组时,Fortran不会检查数组长度,需要确保Python传递的数组长度足够,避免越界访问。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 04:02:44