# C-interoperable Fortran routine with explicit interface

**URL:** https://fortran-lang.discourse.group/t/c-interoperable-fortran-routine-with-explicit-interface/5902
**Category:** Help
**Created:** [June 2, 2023, 8:44pm UTC](https://fortran-lang.discourse.group/t/c-interoperable-fortran-routine-with-explicit-interface/5902 "2023-06-02T20:44:22Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![HugoMVale](https://avatars.discourse-cdn.com/v4/letter/h/e19adc/32.png) [@HugoMVale](https://fortran-lang.discourse.group/u/HugoMVale)
#### Post date: [June 2, 2023, 8:44pm UTC](https://fortran-lang.discourse.group/t/c-interoperable-fortran-routine-with-explicit-interface/5902/1 "2023-06-02T20:44:22Z")

</div>

I trying to learn how to write C-interoperable Fortran procedures. I guess, I got the gist of it for normal type arguments, but I am somewhat lost for procedure arguments.

Let us suppose the following procedure with an explicit interface:

```fortran
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

```

Could the C-interoperable Fortran procedure look like so?

```fortran
real(c_double) function averagefnc_c(fnc, a, b) result(res) bind(c)
  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) ! something is still missing here, I imagine
end function

```

Or is it necessary to transform the explicit interface into an abstract interface and do as described here: [Working with C Pointers (The GNU Fortran Compiler)](https://gcc.gnu.org/onlinedocs/gfortran/Working-with-C-Pointers.html)?

Any hints on documentation and/or an open source project that makes use of such features are also very welcome.

---

<div class="post-metadata">

### Author: ![RobertPincus](https://avatars.discourse-cdn.com/v4/letter/r/a183cd/32.png) [@RobertPincus](https://fortran-lang.discourse.group/u/RobertPincus)
#### Post date: [June 3, 2023, 2:40am UTC](https://fortran-lang.discourse.group/t/c-interoperable-fortran-routine-with-explicit-interface/5902/2 "2023-06-03T02:40:46Z")

</div>

Hi @HugoMVale. Perhaps I misunderstand what you’re doing but this seems slightly over-complicated to me.

All of the “kernels” with public interfaces in [this open-source repo](https://github.com/earth-system-radiation/rte-rrtmgp) are bound to C. Each related set of kernels lives in a module, so the interface is generated from the function definition. Arguments to kernel routines are all C-compatible variables (e.g arrays have to be explicit size), so adding C binding is easy, e.g.

```auto
module mo_fluxes_broadband_kernels
contains
subroutine net_broadband_full(ncol, nlev, ngpt, spectral_flux_dn, spectral_flux_up, broadband_flux_net) &
    bind(C, name="rte_net_broadband_full")
    integer, intent(in ) :: ncol, nlev, ngpt
      !! Array sizes
    real(wp), dimension(ncol, nlev, ngpt), intent(in ) :: spectral_flux_dn, spectral_flux_up
      !! Spectrally-resolved flux up and down
    real(wp), dimension(ncol, nlev), intent(out) :: broadband_flux_net
   ...
  end subroutine

```

Mapping to your code:

```auto
module average
  use, intrinsic :: iso_c_binding
  implicit none
  public :: averagefnc_c
contains 
  function averagefnc_c(fnc, a, b) result(res) bind(c, name = "averagefnc_c")
    real(c_double), intent(in) :: x
    real(c_double), intent(in) :: a, b
    real(c_double) :: res
    real(c_double) :: fnc ! Declared as a scalar - is that what's meant?
    res = averagefnc(fnc, a, b) ! something is still missing here, I imagine
  end function

```

Did that address the question?

---

<div class="post-metadata">

### Author: ![HugoMVale](https://avatars.discourse-cdn.com/v4/letter/h/e19adc/32.png) [@HugoMVale](https://fortran-lang.discourse.group/u/HugoMVale)
#### Post date: [June 3, 2023, 8:03am UTC](https://fortran-lang.discourse.group/t/c-interoperable-fortran-routine-with-explicit-interface/5902/3 "2023-06-03T08:03:24Z")

</div>

Thanks. However, I fell there is a misunderstanding. `fnc` is not a number, it’s a _function_.

---

<div class="post-metadata">

### Author: ![Euler-37](https://avatars.discourse-cdn.com/v4/letter/e/b19c9b/32.png) [@Euler-37](https://fortran-lang.discourse.group/u/Euler-37)
#### Post date: [June 3, 2023, 8:20am UTC](https://fortran-lang.discourse.group/t/c-interoperable-fortran-routine-with-explicit-interface/5902/4 "2023-06-03T08:20:43Z")

</div>

> <https://github.com/fortran-lang/minpack/blob/main/src/minpack_capi.f90>

This Fortran-lang Project MinPack has c func binding,It can be a reference.

and this way also works

```fortran
module func
   use iso_fortran_env,only:dp=>real64
   implicit none
   abstract interface 
      function fnc(x)bind(c)
         import dp
         real(dp), value :: x
         real(dp) :: fnc
      end function
   end interface
contains
   real(dp) function averagefnc(fc, a, b) result(res)bind(c,name="averagefnc_api")
      real(dp), value :: a, b
      procedure(fnc)::fc
      res = (fc(a) + fc(b))/2
   end function
end module func

```

```c
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
double averagefnc_api(double(*func)(double),double ,double);
double func(double x){
   return sin(x);
}

int main(){
   printf("%lf\n",averagefnc_api(func,1.0,2.0));
}

```

---

<div class="post-metadata">

### Author: ![HugoMVale](https://avatars.discourse-cdn.com/v4/letter/h/e19adc/32.png) [@HugoMVale](https://fortran-lang.discourse.group/u/HugoMVale)
#### Post date: [June 4, 2023, 3:49pm UTC](https://fortran-lang.discourse.group/t/c-interoperable-fortran-routine-with-explicit-interface/5902/5 "2023-06-04T15:49:34Z")

</div>

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

```fortran
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

```

```auto
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

```

```c
#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));
}

```
