Fortran-C interoperability and float arrays
c, fortran, fortran-iso-c-binding
Solution
First, I assume you define dp as a parameter in a module somewhere. You can simply use
integer, parameter :: dp = c_double
in that module (and have `if (dp /= c_double) stop "Bletchful sytem"` somewhere.
Passing an array between C and Fortran works like this:
module foo
use iso_c_binding
private
public :: bar
interface
subroutine bar(a,n) bind(C)
import
real(kind=c_double), dimension(*), intent(inout) :: a
integer(c_size_t), value, intent(in) :: n
end subroutine bar
end interface
end module foo
Your C function then would be
void bar(double *a, size_t n)
Edit:
The way to call your C function from Fortran would then be
program main
use iso_c_binding
use foo
real(c_double), dimension(10) :: a
call bar(a,size(a,kind=c_size_t))
print *,a
end program main
Edit 2:
If you really want to do copy-in / copy-out each time, you can do something like
subroutine bar2(array)
real(kind=c_double), intent(inout), dimension(:) :: array
real(kind=c_double), dimension(size(array)) :: a
a = array ! Copy in
call bar(a,size(a,kind=c_size_t))
array = a ! Copy out
end subroutine bar2
end module foo
But I am at a loss to understand why this would be necessary.
Edit 3:
If you are afraid of a mismatch between C and Fortran datatypes, you can write a generic wrapper to get around this. This is what it could look like:
module foo
use iso_c_binding
implicit none
private
public :: bar
interface
subroutine bar_double(a,n) bind(C)
import
real(kind=c_double), dimension(*), intent(inout) :: a
integer(c_size_t), value, intent(in) :: n
end subroutine bar_double
end interface
interface
subroutine bar_float(a,n) bind(C)
import
real(kind=c_float), dimension(*), intent(inout) :: a
integer(c_size_t), value, intent(in) :: n
end subroutine bar_float
end interface
interface bar
module procedure bar_aux_double, bar_aux_float
end interface bar
contains
subroutine bar_aux_double (a)
real(kind=c_double), dimension(:), intent(inout) :: a
call bar_double (a, size(a,kind=c_size_t))
end subroutine bar_aux_double
subroutine bar_aux_float (a)
real(kind=c_float), dimension(:), intent(inout) :: a
call bar_float (a, size(a,kind=c_size_t))
end subroutine bar_aux_float
end module foo
Your main program then could look like
program main
use foo
integer, parameter :: dp = selected_real_kind(15)
integer, parameter :: sp = selected_real_kind(6)
real(dp), dimension(10) :: a_dp
real(sp), dimension(10) :: a_sp
call bar(a_dp)
call bar(a_sp)
print *,a_dp,a_sp
end program main
where you don't make any reference to iso_c_binding at all. If there is no wrapper function for dp or sp, compilation will fail for lack of a generic procedure.
Problem
I have a large existing Fortran95 code. It uses ``` real(dp), dimension(num) :: array ``` to declare arrays. I want to join in some C code and found that I can do this by writing interfaces to the C-functions and declaring arrays as ``` use iso_c_binding real(c_double), allocatable, target :: array(:) ``` I have working fortran functions which call the C-functions as ``` call myfunction(c_loc(array)); ``` What is needed to pass the `real(dp)` array to myfunction? Apparently, I would need to make a C-pointer from it (how?). Is there any other way than copying the array? Is it possible to ensure that both types indeed refer to compatible double precision data blocks? Most importantly the solution must work with the GNU compilers. Note, that replacing `real(dp)` with `real(c_double)` everywhere in the existing Fortran code is not an option for me right now. In case there is no alternative to copying the entire array, how would I do this properly in the interface?