Interoperability of assumed-rank arguments (TS 29113)
To facilitate the interoperability with C functions that
accept arguments of arbitrary rank including scalar arguments, assumed-rank
arguments are introduced in Fortran.
Rules
If a C descriptor is for a nonallocatable
nonpointer assumed-rank argument, the following rules apply:
- The attribute member of the C descriptor is CFI_attribute_other.
- The lower_bound member of each element of the dim member of the C descriptor is zero.
The lower bound of every dimension of a nonallocatable nonpointer assumed-rank argument on the Fortran side is always one.
If a dummy argument in an interoperable interface is assumed-rank, the corresponding C formal parameter is interpreted as the address of a C descriptor.
For an interoperable procedure with a Fortran
interface that has an assumed-rank dummy argument with the CONTIGUOUS attribute,
the associated actual argument can be noncontiguous.
- If the procedure is invoked from Fortran or the procedure is a Fortran procedure, XL Fortran ensures that the assumed-rank dummy argument is contiguous.
- If the procedure is invoked from C and the procedure is a C procedure, the C procedure must handle the noncontiguous arguments that might be passed to it.
Restrictions:
- If a procedure has an assumed-rank dummy argument, the procedure must have an explicit interface.
- If an object is passed to a Fortran procedure as a nonallocatable nonpointer assumed-rank dummy argument, the lifetime of the object cannot end before the return from the procedure call.
- In the following situations, the C descriptor cannot be modified:
- Its address is a formal parameter that corresponds to a Fortran actual argument and the corresponding dummy argument in the Fortran interface is for a nonallocatable nonpointer assumed-rank argument.
- Its address is a C actual argument that corresponds to a Fortran dummy argument and the corresponding dummy argument in the Fortran interface is for a nonallocatable nonpointer assumed-rank argument.
Examples
This example calls the do_square() function from the Fortran side to calculate the square of every second element of each array, such as scalar objects, one-dimensional, and two-dimensional arrays.PROGRAM mysquare
USE, INTRINSIC :: iso_c_binding
IMPLICIT NONE
INTERFACE
SUBROUTINE do_square(x) BIND(C)
IMPORT
INTEGER(C_INT), INTENT(INOUT) :: x(..)
END
END INTERFACE
INTEGER :: i
INTEGER(C_INT) :: v_scalar = -1
INTEGER(C_INT), TARGET :: v_1d(10) = [(i, i=1,10,1)]
INTEGER(C_INT), TARGET :: v_2d(10,3) = RESHAPE([(i, i=1,30,1)], [10,3])
INTEGER(C_INT), POINTER :: p_1d(:), p_2d(:,:)
PRINT *, "before value of scalar:", v_scalar
PRINT *, "before value of vector:", v_1d
PRINT *, "before value of 2D:", v_2d
! Square the scalar value.
CALL do_square(v_scalar)
! Square every second element of each array.
p_1d => v_1d(::2)
p_2d => v_2d(::2,::2)
CALL do_square(p_1d)
CALL do_square(p_2d)
PRINT *, "after value of scalar:", v_scalar
PRINT *, "after value of vector:", v_1d
PRINT *, "after value of 2D:", v_2d
END
The do_square() function is defined
as follows on the C side:#include <assert.h>
#include "ISO_Fortran_binding.h"
void do_square(CFI_cdesc_t * x)
{
assert(x->type == CFI_type_int);
switch (x->rank)
{
case 0:
{
int v = *(int *)x->base_addr;
*(int *)x->base_addr = v * v;
}
break;
case 1:
{
char * p = (char *)x->base_addr;
int i;
char * tp = p;
for(i = 0; i < x->dim[0].extent; i++)
{
int v = *(int *)tp;
*(int *)tp = v * v;
tp += x->dim[0].sm; // Advance to the next element.
}
}
break;
case 2:
{
CFI_index_t extents[2];
CFI_index_t strides[2];
int i, j;
char * p = (char *)x->base_addr;
extents[0] = x->dim[0].extent;
extents[1] = x->dim[1].extent;
strides[0] = x->dim[0].sm;
strides[1] = x->dim[1].sm;
for(i = 0; i < extents[1]; i++)
{
char * tp = p;
for(j = 0; j < extents[0]; j++)
{
int v = *(int *)tp;
*(int *)tp = v * v;
tp += strides[0]; // Advance to the next element in dimension 1.
}
p += strides[1]; // Advance to the next element in dimension 2.
}
}
break;
default:
assert(0);
break;
}
return;
}
The output is as follows:before value of scalar: -1
before value of vector: 1 2 3 4 5 6 7 8 9 10
before value of 2D: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
after value of scalar: 1
after value of vector: 1 2 9 4 25 6 49 8 81 10
after value of 2D: 1 2 9 4 25 6 49 8 81 10 11 12 13 14 15 16 17 18 19 20 441 22 529 24 625 26 729 28 841 30


