Iso_c_binding: pass an array from c to fortran (Edit: python interop content)

@hsnyder and any readers needing to interoperate Fortran codes with a companion C processor:

You may note many of the feature sets in Fortran starting with Fortran 90 thru’ Fortran 2018 can really prove useful in scientific and technical computing contexts, classic examples would be ASSUMED-SHAPE arrays, dummy arguments with ALLOCATABLE attribute, etc. With this in mind, note a “trivial” subprogram in modern Fortran can be as follows where the array descriptors are part of the dummy argument itself thereby making it unnecessary to pass additional arguments:

   ..
   subroutine Fsub( x ) bind(C, name="Fsub")
      ! Argument list
      real(kind=CF), intent(inout) :: x(:)  !<-- assumed-shape
..

Then if your strengths are in programming in C, C++, note with some additional effort, you can layer your C code to interoperate with Fortran’s strengths using the enhanced interoperability facility introduced in Fortran 2018 via “ISO_Fortran_binding.h” header. The standard for Fortran provides details on this, as does the book by Metcalf et al., “Modern Fortran Explained”

Here is a modified example of your code: as you will notice, it is an overkill in simple scenarios, but it can prove handy when it comes to consuming performant Fortran codes with a companion C processor.

#include <stdlib.h>
#include <stdio.h>
#include "ISO_Fortran_binding.h"

extern void Fsub(CFI_cdesc_t *);

int main(void)
{
   enum N { N = 4 };
   float x[N];
   int i;
   CFI_CDESC_T(1) dat; // employ a macro defined in Fortran binding header
   CFI_index_t ext[1]; // employ a type defined in Fortran binding header

   ext[0] = (CFI_index_t)N;
   i = CFI_establish((CFI_cdesc_t *)&dat, x, CFI_attribute_other,
                      CFI_type_float, 0, (CFI_rank_t)1, ext);

   Fsub((CFI_cdesc_t *)&dat );
   printf("In C main: following call to Fsub, x = \n");
   for (i=0; i<N-1; i++) printf("%f, ", x[i]); printf("%f\n", x[N-1]);

   return EXIT_SUCCESS;
}
module m
   use, intrinsic :: iso_c_binding, only : CF => c_float
contains
   subroutine Fsub( x ) bind(C, name="Fsub")
      ! Argument list
      real(kind=CF), intent(inout) :: x(:)
      integer :: i
      print *, "In Fsub: shape(x) = ", shape(x)
      x = [( real(i,kind=CF), i=lbound(x,dim=1),ubound(x,dim=1) )]
   end subroutine 
end module 

C:\Temp>ifort /c /standard-semantics /warn:all /stand:f18 m.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.1 Build 20201112_000000
Copyright (C) 1985-2020 Intel Corporation. All rights reserved.

C:\Temp>cl /c /EHsc /W3 c.c
Microsoft (R) C/C++ Optimizing Compiler Version 19.26.28806 for x64
Copyright (C) Microsoft Corporation. All rights reserved.

c.c

C:\Temp>link c.obj m.obj /subsystem:console /out:p.exe
Microsoft (R) Incremental Linker Version 14.26.28806.0
Copyright (C) Microsoft Corporation. All rights reserved.

C:\Temp>p.exe
In Fsub: shape(x) = 4
In C main: following call to Fsub, x =
1.000000, 2.000000, 3.000000, 4.000000

C:\Temp>

1 Like