I am working to encapsulate a C library using f2py (to later use them in python/numpy). After getting help here to get the first encapsulation working I am now trying to encapsulate more complex types, specifically C functions returning arrays allocated via malloc
.
This is the C library mockup (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;
}
I can succesfully encapsulate the basic multiply_numbers
function (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
I compile everything using this 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 am struggling to understand how would I code the subroutine that wraps the C function get_array
.
Specifically,
- how do I receive a 100 items array?
- which would be the interface definition?
Note: I have not tried anything because I do not where to start.
EDIT
With francescalous comments I have been able to encapsulate the function and make it work. It is worth to note that f2py
might require the extra step of assigning the Fortran pointer to a Fortran array. I am not sure on this point but I can not get f2py compiled when trying to output the Fortran pointer directly.
This is the final wrapper subroutine in Fortran for 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