Reputation: 5505
I have the following test library written in C, one function allocates an array and the other one is intended to free that memory. Note that the returned array is passed as pointer to pointer as in the real application I will need functions returning several arrays:
#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);
}
And the corresponding wrapper which uses iso_c_binding
and f2py
:
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
And the corresponding 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
But I get:
xxx | c_z = loc(z)
| 1
Error: Cannot convert INTEGER(8) to TYPE(c_ptr) at (1)
There might be more issues or bad practices in the way both routines are constructed, but the above code is what I have tried.
type(c_ptr) :: c_z(*)
in Fortran the right way to specify int **myarray
in C?I am using gfortran in FreeBSD12.
EDIT
Following Vladimir´s answer I recode free_integer_array
incorporating two changes:
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
Then I consume the library generated by f2py as follows:
>>> 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)
So far so good, a numpy array is returned. Then I want to free it:
>>> free_integer_array(a)
And here kernel dies after a while, no other info in the Jupyter Notebook log other than [Errno 79] Inappropriate file type or format
, but not even sure that is related to Jupyter Notebook or to the actual program.
Upvotes: 0
Views: 157
Reputation: 60058
To get a type(c_ptr)
pointer one uses c_loc()
. I stead, the loc()
function is to get an integer containg the addres - usable for Cray (integer) pointers.
Upvotes: 1