Search code examples
visual-c++fortranintel-fortranfortran-iso-c-binding

About using Fortran function in C with iso_c_binding


I learn Fortran's C interoperability for a few days to call a Fortran function DLL from C. Here I found this link: Use Fortran-code in C

I try to create a Fortran DLL like this and my compiler is Intel Fortran compiler:

module integration
  implicit none

contains

  function Integrate(func, a,b, intsteps) result(integral)
!DEC$ ATTRIBUTES DLLEXPORT :: Integrate
    interface
      real function func(x)
        real, intent(in) :: x
      end function func
    end interface

    real :: integral, a, b
    integer :: intsteps
    intent(in) :: a, b, intsteps
    optional :: intsteps

    real :: x, dx
    integer :: i,n
    integer, parameter :: rk = kind(x)

    n = 1000
    if (present(intsteps)) n = intsteps

    dx = (b-a)/n

    integral = 0.0_rk
    do i = 1,n
      x = a + (1.0_rk * i - 0.5_rk) * dx
      integral = integral + func(x)
    end do

    integral = integral * dx
  end function

end module integration


    real(c_float) function wrapper_integrate(func, a, b, intsteps) result(integral) bind(C, name='integrate')
  use iso_c_binding
  use integration

 interface
    function iFunc(x) bind(C)
      use, intrinsic :: iso_c_binding
      real(c_float) :: iFunc
      real(c_float), intent(in) :: x
    end function iFunc
  end interface

  type(C_FUNPTR), INTENT(IN), VALUE :: func
  real(c_float) :: a,b
  integer(c_int),intent(in) :: intsteps
  optional :: intsteps

  procedure(iFunc),pointer :: myfunc
  call c_f_procpointer(func, myfunc)

  if (present(intsteps)) then
    integral = Integrate(myfunc,a,b,intsteps)   <==error #8128
  else
    integral = Integrate(myfunc,a,b)          <==error #8128
  endif

end function wrapper_integrate

When I built the DLL, the error shows below

error #8128: The BIND attribute of the associated actual procedure differs from the BIND attribute of the dummy procedure.   [MYFUNC]

The error line denoted in code, it looks like myfunc is not equal to func defined in module integration. Maybe I can use the iso_c_binding to modify module integration.

Sometimes some Fortrans function have many arguments to be assigned and used in the function, it is not easy way to use iso_c_binding in Fortran. So how to solve the error in MYFUNC?


Solution

  • If a dummy procedure has an explicit interface, then its characteristics must be the same as the characteristics of the actual procedure, except for some things not relevant here.

    The characteristics of a procedure include whether it has the BIND attribute.

    To make the characteristics consistent you can use a little intermediate procedure, that does not have BIND(C), to call your supplied BIND(C) procedure.

    For example, with some other changes to avoid assumptions around whether c_float and c_int nominated default real and integer kinds:

    function wrapper_integrate(func, a, b, intsteps)  &
        result(integral) bind(C, name='integrate')
      use iso_c_binding
      use integration
      implicit none
    
      interface
        function func(x) bind(C)
          use, intrinsic :: iso_c_binding
          implicit none
          real(c_float), intent(in) :: x
          real(c_float) :: func
        end function func
      end interface
    
      real(c_float), intent(in) :: a,b
      integer(c_int), intent(in), optional :: intsteps
      real(c_float) :: integral
    
      real :: local_a, local_b
      integer :: local_intsteps
    
      local_a = a
      local_b = b
      if (present(intsteps)) then
        local_intsteps = intsteps
        integral = Integrate(local_func, a, b, local_intsteps)
      else
        integral = Integrate(local_func, a, b)
      end if
    contains
      function local_func(x)
        real, intent(in) :: x
        real :: local_func
    
        real(c_float) :: local_x
    
        local_x = x
        local_func = func(local_x)
      end function local_func
    end function wrapper_integrate
    

    Note that the presence of optional arguments in an interoperable procedure is a Fortran 2015 feature.