redwizard792 redwizard792 - 1 year ago 57
C Question

What's the right way to pass a Fortran zero-length arrays to C?

I have the following kind of subroutine wrapper to pass a Fortran array to a

ISO_C_BINDING
-bound C function.

subroutine mysub( array )
integer, dimension(:) :: array
call f_mysub( size(array) , array(1) )
end subroutine


The problem is that if the array is of size 0 then
array(1)
is out-of-bounds. What's the right way to handle this situation?

In general I cannot avoid the call, i.e. with a
if( size(array) > 0 )
because the call may be important to register, e.g. it is actually a class method, naturally with different signature than above, and could clear an existing array.

Example Files



The C routine is
c_mysub.c
.

#include <stdio.h>
void c_mysub( size_t* size, int* arr )
{
printf("size=%d\n",*size);
for(size_t i=0; i<*size; ++i)
{
printf("element %d=%d\n",i,arr[i]);
}
}


The main Fortran file is
mysub.f90


module mysub_I
interface
subroutine f_mysub( size, arr) BIND(C,name="c_mysub")
use,intrinsic :: ISO_C_BINDING
integer(C_SIZE_T) :: size
integer(C_INT) :: arr
end subroutine
end interface
end module

module mysub_M
use mysub_I
contains

subroutine mysub( array )
use ISO_C_BINDING
integer, dimension(:) :: array
call f_mysub( int(size(array),C_SIZE_T) , array(1) )
end subroutine

end module

program main
use mysub_M
integer, allocatable :: x(:)

allocate( x(7) )
x=1

call mysub( x )

deallocate( x )
allocate( x(0) )

call mysub( x )

end


Compile the C with
gcc -c c_mysub.c
and the Fortran with
gfortran -fbounds-check c_mysub.o mysub.f90
, which gives the following error when you run the code, balking at the second call with size=0.

size=7
0:1
1:1
2:1
3:1
4:1
5:1
6:1
At line 18 of file mysub.f90
Fortran runtime error: Index '1' of dimension 1 of array 'array' above upper bound of 0


Compiling with bounds check off behaves as expected.

size=7
0:1
1:1
2:1
3:1
4:1
5:1
6:1
size=0

Answer Source

I do not see any reason to pass array(1) as actual argument. The whole array array should be passed.

  call f_mysub( size(array) , array )

and the interface must be changed to pass an array and not just a scalar

  integer(C_INT) :: arr(*)

Passing the first element (even to an array argument) could easily cause incorrect behaviour if array is not contiguous - which is theoretically possible given it is assumed shape dummy argument (with (:)).

If you pass the whole array and size 0 then just make sure no element is actually dereferenced from the pointer in the C procedure (which should already be the case if it is well-written).

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download