【问题标题】:How do you free memory allocated in a function invoked via iso_c_binding and then passed to python via f2py?如何释放通过 iso_c_binding 调用的函数中分配的内存,然后通过 f2py 传递给 python?
【发布时间】:2021-07-24 10:49:08
【问题描述】:

我有以下用 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 或实际程序有关。

【问题讨论】:

    标签: fortran gfortran f2py fortran-iso-c-binding


    【解决方案1】:

    要获得type(c_ptr) 指针,请使用c_loc()。我认为,loc() 函数是获取包含地址的整数 - 可用于 Cray(整数)指针。

    【讨论】:

    • 解决了一个问题,我还在free_integer_array 中将integer, pointer :: z(:) 修改为integer, pointer :: z,一切都编译好了,但是当我尝试在python free_integer_array 中调用@987654328 返回的numpy 数组时@内核死了,所以我仍然没有正确理解。
    • @M.E.也许这条线type(c_ptr) :: c_array(*) 需要是type(c_ptr), value :: c_array? (因为对应的C函数接收的是一个指针变量的值)
    猜你喜欢
    • 2016-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-31
    • 1970-01-01
    • 2020-12-06
    相关资源
    最近更新 更多