Thanks for pointing me to the minpack project. That is indeed a good source of inspiration. 
The answer you provided was not quite yet what I was looking for, but it made me realize what the problem was.
I want to keep the function averagefnc (this is just a toy procedure) as a normal Fortran function. It’s C-counterpart averagefnc_c is meant as a wrapper to allow one to invoke averagefnc from C. Since fnc will ultimately be called inside averagefnc it must, like normal Fortran functions, have the argument(s) passed by reference not by value.
So, the issue was not on the Fortran side, but on the C-side. As shown below it works fine
module fmodule
!! A module with various toy functions and subroutines to learn how to invoke fortran code
!! from python.
use, intrinsic :: iso_fortran_env, only: real32, real64
implicit none
private
public :: intsum, real4sum, real8sum, vector4sum, matrix8sum, saxpy, matrixtimesvector
public :: averagefnc
integer, parameter :: sp = real32
integer, parameter :: dp = real64
contains
! ...
real(dp) function averagefnc(fnc, a, b) result(res)
!! Average of function with explicit interface
interface
function fnc(x)
import dp
real(dp), intent(in) :: x
real(dp) :: fnc
end function
end interface
real(dp), intent(in) :: a, b
res = (fnc(a) + fnc(b))/2
end function
end module fmodule
module fmodule_bindings
use fmodule
use iso_c_binding, only: c_float, c_double, c_int
implicit none
abstract interface
function fx_c(x) bind(c)
import c_double
real(c_double), intent(in) :: x
real(c_double) :: fx_c
end function
end interface
contains
! ...
real(c_double) function averagefnc_abstract_c(fnc, a, b) result(res) bind(c, name='averagefnc_abstract')
procedure(fx_c) :: fnc
real(c_double), intent(in) :: a, b
res = averagefnc(fnc, a, b)
end function
real(c_double) function averagefnc_explicit_c(fnc, a, b) result(res) bind(c, name='averagefnc_explicit')
interface
function fnc(x) bind(c)
import c_double
real(c_double), intent(in) :: x
real(c_double) :: fnc
end function
end interface
real(c_double), intent(in) :: a, b
res = averagefnc(fnc, a, b)
end function
end module fmodule_bindings
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
double averagefnc_abstract(double(*func)(double*), double*, double*);
double averagefnc_explicit(double(*func)(double*), double*, double*);
double func(double* x){
return *x;
}
int main(){
double a = 1.;
double b = 2.;
printf("%lf\n", averagefnc_abstract(func, &a, &b));
a = 3.;
b = 4.;
printf("%lf\n", averagefnc_explicit(func, &a, &b));
}