Reputation: 477
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
Reputation: 60088
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