微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何释放通过 iso_c_binding 调用的函数中分配的内存,然后通过 f2py 传递给 python?

如何解决如何释放通过 iso_c_binding 调用的函数中分配的内存,然后通过 f2py 传递给 python?

我有以下用 C 编写的测试库,一个函数分配一个数组,另一个函数用于释放该内存。请注意,返回的数组作为指向指针的指针传递,就像在实际应用程序中一样,我将需要返回多个数组的函数

#include <stdlib.h>
#include <stdio.h>
void return_array(int length,int **myarray);
void free_array(void *myarray);

void return_array(int length,int **myarray) {
        int i;
        *myarray =  malloc(length*sizeof(int));
        for(i=0; i<length; i++) {
                (*myarray)[i] = i+1;
        }
}

void free_array(void *myarray) {
        free(myarray);
}

以及使用 iso_c_bindingf2py 的相应包装器:

module test_c_lib

        use iso_c_binding
        implicit none
    
contains

    subroutine return_array(l,z)

            use iso_c_binding

            integer,intent(in) :: l
            integer,intent(out) :: z(l)

            type(c_ptr) :: ret_c_ptr
            integer,pointer :: f_ptr(:)

            interface
                    subroutine c_return_array(c_l,c_z) bind(C,name="return_array")
                            import
                            integer(c_int),value :: c_l
                            type(c_ptr) :: c_z(*)
                    end subroutine
            end interface

            call c_return_array(10,ret_c_ptr)
            call c_f_pointer(ret_c_ptr,f_ptr,[l])
            z = f_ptr
    end subroutine

    subroutine free_integer_array(z)

            use iso_c_binding

            integer,pointer :: z(:)
            type(c_ptr) :: c_z

            interface
                    subroutine c_free_array(c_array) bind (C,name="free_array")
                            import
                            type(c_ptr) :: c_array(*)
                    end subroutine
            end interface

            c_z = loc(z)
            call c_free_array(c_z)

    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

但我明白了:

  xxx |                 c_z = loc(z)
      |                      1
Error: Cannot convert INTEGER(8) to TYPE(c_ptr) at (1)

这两个例程的构建方式可能存在更多问题或不良做法,但上面的代码是我尝试过的。

  • 这两个步骤公开的 C 函数将如何实现?
  • 对于每种类型的数组(整数、实数等),我是否需要在 Fortran 中使用一个免费例程?
  • Fortran 中的 type(c_ptr) :: c_z(*) 是否是在 C 中指定 int **myarray 的正确方法

我在 FreeBSD12 中使用 gfortran。

编辑

按照 Vladimir 的回答,我重新编码了 free_integer_array,包含两个更改:

    subroutine free_integer_array(z)

            use iso_c_binding

            integer,pointer :: z
            type(c_ptr) :: c_z

            interface
                    subroutine c_free_array(c_array) bind (C,name="free_array")
                            import
                            type(c_ptr) :: c_array(*)
                    end subroutine
            end interface

            c_z = c_loc(z)
            call c_free_array(c_z)

    end subroutine

然后我使用f2py生成的库如下:

>>> import f_mod
>>> a = f_mod.test_c_lib.return_array(10)
>>> a
array([ 1,2,3,4,5,6,7,8,9,10],dtype=int32)

到目前为止一切顺利,返回了一个 numpy 数组。然后我想释放它:

>>> free_integer_array(a)

这里内核在一段时间后死亡,除了 [Errno 79] Inappropriate file type or format 之外,Jupyter Notebook 日志中没有其他信息,但甚至不确定这与 Jupyter Notebook 或实际程序有关。

解决方法

要获得 type(c_ptr) 指针,可以使用 c_loc()。相反,loc() 函数是获取一个包含地址的整数 - 可用于 Cray(整数)指针。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。