I have the following C library (in particular the function I am debugging now is pass_by_reference):
#include <stdlib.h>
double multiply_numbers(double a, double b);
double *get_array(double a);
void pass_by_reference(int *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;
}
void pass_by_reference(int *a) {
*a = 8;
}
And I am trying to get this wrapped by a Fortran subroutine named pass_by_reference (to be latter called via f2py in python):
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
subroutine get_array(x, z)
use iso_c_binding
real(8), intent(in) :: x
real(8), intent(out) :: z(100)
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])
z = f_ptr
end subroutine
subroutine pass_by_reference(z)
use iso_c_binding
integer, intent(out) :: z
! Interface to C function
interface
type(c_null_ptr) function c_pass_by_reference(a) bind(C, name="pass_by_reference")
import
type(c_int), value :: a
end function
end interface
! Call C function
c_pass_by_reference(z)
end subroutine
end module
And the corresponding makefile:
$ cat 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
When trying to get this compiled with f2py I get:
57 | use iso_c_binding
| 2
......
63 | type(c_null_ptr) function c_pass_by_reference(a) bind(C, name="pass_by_reference")
| 1
Error: Type name 'c_null_ptr' at (1) conflicts with previously declared entity at (2), which has the same name
f_mod.f90:65:43:
57 | use iso_c_binding
| 2
......
65 | type(c_int), value :: a
| 1
Error: Type name 'c_int' at (1) conflicts with previously declared entity at (2), which has the same name
f_mod.f90:63:24:
63 | type(c_null_ptr) function c_pass_by_reference(a) bind(C, name="pass_by_reference")
| 1
Error: The type for function 'c_pass_by_reference' at (1) is not accessible
f_mod.f90:63:24: Warning: Implicitly declared BIND(C) variable 'c_pass_by_reference' at (1) may not be C interoperable [-Wc-binding-type]
f_mod.f90:70:35:
70 | c_pass_by_reference(z)
| 1
Error: 'c_pass_by_reference' at (1) is not a variable
f_mod.f90:63:24-71:
63 | type(c_null_ptr) function c_pass_by_reference(a) bind(C, name="pass_by_reference")
| 2 1
Warning: Implicitly declared variable 'a' at (1) may not be C interoperable but it is a dummy argument to the BIND(C) procedure 'c_pass_by_reference' at (2) [-Wc-binding-type]
f_mod.f90:63:24:
63 | type(c_null_ptr) function c_pass_by_reference(a) bind(C, name="pass_by_reference")
| 1
Warning: Implicitly declared BIND(C) function 'c_pass_by_reference' at (1) may not be C interoperable [-Wc-binding-type]
error: Command "/usr/local/bin/gfortran9 -Wall -g -fno-second-underscore -fPIC -O3 -funroll-loops -I/tmp/tmpk7tn1bgi/src.freebsd-12.2-RC1-amd64-3.7 -I/usr/local/lib/python3.7/site-packages/numpy/core/include -I/usr/local/include/python3.7m -c -fPIC f_mod.f90 -o /tmp/tmpk7tn1bgi/f_mod.o -J/tmp/tmpk7tn1bgi/ -I/tmp/tmpk7tn1bgi/" failed with exit status 1
*** Error code 1
I have two questions:
- When
iso_c_bindingis used, and in this particular example, is the variableapassed topass_by_referencefunction actually passed by reference or do I have to specify something different in the interface? - Why
f2pyis reportingType name 'c_int' at (1) conflicts with previously declared entity at (2), which has the same name? - How do I specify that the C function does not return anything (
void)? I have tried to usetype(c_null_ptr)

type(c_int)should beinteger(c_int).c_null_ptris a constant of typec_ptrnot a type itself. (C functions with void return map to Fortran subroutines.)valueattribute specification forais a good hint that it is passed by value, not by reference.f_mod.f90:70:35: 70 | c_pass_by_reference(z) Error: 'c_pass_by_reference' at (1) is not a variable