jcerar
jcerar

Reputation: 477

Fortran to C interface for arrays and scalars

I am learning how to interface Fortran with C. I wrote as simple C code that sets all array values to 1:

#include <stdlib.h>
void cset( int *array, int size ) {
  for (size_t i = 0; i < size; i++) {
    array[i] = 1;
  }
  return;
}

I wanted to write a Fortran interface to work for both arrays (of any dimension) and scalars.
My fortran code:

program main
  use iso_c_binding
  implicit none

  interface cset
    ! Interface for arrays.
    subroutine cset_array( array, size ) bind( C, NAME="cset" )
      import
      integer(C_INT), intent(inout)     :: array(*)
      integer(C_INT), value, intent(in) :: size
    end subroutine cset_array

    ! Interface for scalars. NOTE: Fortran values are passed by reference (so this should work)
    subroutine cset_scalar( scalar, size ) bind( C, NAME="cset" )
      import
      integer(C_INT), intent(inout)     :: scalar
      integer(C_INT), value, intent(in) :: size
    end subroutine cset_scalar

  end interface cset

  integer :: scalar = 0
  integer :: array(3) = 0
  integer :: array2d(3,3) = 0

  call cset( scalar, 1 )
  print *, scalar

  call cset( array, size(array) )
  print *, array

  ! Does not work???
  ! call cset( array2d, size(array2d) )

  ! But works for
  call cset_array( array2d, size(array2d) )
  ! OR call cset( array2d(1,1), size(array2d) )
  print *, array2d

end program main

This works for scalars and 1D arrays jst fine.

Why does the interface not work for the cset( array2d, size(array2d) ), but works for cset_array( array2d, size(array2d) ) or call cset( array2d(1,1), size(array2d) )? In the first case I get the following error (gfortran-7.4):

call cset( array2d, size(array2d) )
                                  1
Error: There is no specific subroutine for the generic ‘cset’ at (1)

Is there a more 'proper' way of writing such interface? Is it even ok to pass scalar in such way?

Thank you and kind regards.

RELATED:
Passing a two dimentional array from Fortran to C
Passing both scalars and arrays (of any dimensions) from Fortran to C

Upvotes: 4

Views: 375

Answers (1)

You cannot use assumed size arrays (dimension(*)) to allow the same specific procedure to be used for arrays of multiple ranks (dimensions). Because of the TKR rules (type, kind, rank), all specific procedures are for one rank only. If you try to pass a different rank array to the generic procedure, the specific procedure will not be recognized even if it is possible to pass the array into the specific procedure directly.

The only solution I am aware of is to make specific procedure interfaces for each rank separately.

subroutine cset_array1( array, size ) bind( C, NAME="cset" )
  import
  integer(C_INT), intent(inout)     :: array(*)
  integer(C_INT), value, intent(in) :: size
end subroutine cset_array1

subroutine cset_array2( array, size ) bind( C, NAME="cset" )
  import
  integer(C_INT), intent(inout)     :: array(1,*)
  integer(C_INT), value, intent(in) :: size
end subroutine cset_array2

If you have only one procedure that can accept really anything, like MPI procedures so, one can use the compiler specific

!$GCC attributes no_arg_check

or the same with !$DEC

Upvotes: 3

Related Questions