如何在 Fortran 中使用 iso_c_binding 接收数组

问题描述

我正在使用 f2py 封装一个 C 库(稍后在 python/numpy 中使用它们)。在获得帮助 here 使第一个封装工作后,我现在尝试封装更复杂的类型,特别是返回通过 malloc 分配的数组的 C 函数

这是 C 库模型 (c_lib.c):

#include <stdlib.h>

double multiply_numbers(double a,double b);
double *get_array(double a);

double multiply_numbers(double a,double b) {
        return a*b;
}

double *get_array(double a) {
        double *retval;
        int i;

        retval = malloc(100*sizeof(a));

        for(i=0; i<100; i++) {
                retval[i] = i*a;
        }

        return retval;
}

我可以成功封装基本的multiply_numbers函数(f_mod.f90):

module test_c_lib

        use iso_c_binding
        implicit none
        
contains

        subroutine multiply(x,y,z)

                use iso_c_binding

                real(8),intent(in)        :: x
                real(8),intent(in)        :: y
                real(8),intent(out)       :: z
        
                ! Interface to C function
                interface                        
                        real(c_double) function c_multiply_numbers(a,b) bind(C,name="multiply_numbers")
                                import
                                real(c_double),value :: a,b
                        end function
                end interface

                ! Call C function               
                z = c_multiply_numbers(x,y)                

        end subroutine
        
end module

我使用这个 makefile 编译所有东西:

f_mod.so:       f_mod.f90 c_lib.o
                f2py -c f_mod.f90 c_lib.o -m f_mod

c_lib.o:        c_lib.c
                gcc -c -fpic c_lib.c -o c_lib.o

但是我正在努力理解如何编写包装 C 函数 get_array 的子例程。

具体来说,

  • 如何接收 100 件物品的数组?
  • 哪个是接口定义?

注意:我没有尝试任何东西,因为我不知道从哪里开始。

编辑

通过大量的注释,我已经能够封装该函数并使其工作。值得注意的是,f2py 可能需要将 Fortran 指针分配给 Fortran 数组的额外步骤。在这一点上我不确定,但是在尝试直接输出 Fortran 指针时无法编译 f2py。

这是 Fortran 中 f2py 的最终包装子例程:

    subroutine get_array(x,z)

            use iso_c_binding

            real(8),intent(in)        :: x
            real(8),intent(out)       :: z(100)
            
            ! Auxiliary variables to convert C pointer to Fortran Array
            type(c_ptr)                :: ret_c_ptr
            real(8),pointer           :: f_ptr(:)
    
            ! Interface to C function
            interface                        
                    type(c_ptr) function c_get_array(a) bind(C,name="get_array")
                            import
                            real(c_double),value :: a
                    end function
            end interface

            ! Call C function               
            ret_c_ptr = c_get_array(x)                
            call c_f_pointer(ret_c_ptr,f_ptr,[100])
            
            ! Assign Fortran pointer to Fortran output array       
            z = f_ptr

    end subroutine

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)