Jean Zay: Calling Fortran procedures from C

Some useful recommendations:

  • The Fortran 2003 standard has defined a way of interfacing the Fortran procedures with functions written in C. We recommend this solution because it both ensures portability and allows any Fortran data types to interoperate with those of C language.\\For more complete information, refer to Chapter 9 of the Fortran 2003 course: Interoperability between C and Fortran.
  • In Fortran, parameter passing is effectuated by address whereas in C it is done by value.
  • It is recommended to do the linking with a Fortran compiler. If using the ifort compiler, the -nofor-main option is necessary to indicate that this is not the Fortran main function.

Be aware that if you do not choose the interoperability solution proposed by Fortran 2003, you will have the following restrictions:

  • When C activates a Fortran procedure, the arguments furnished during the call must be addresses of objects with a pre-defined type.
  • During the compilation of the Fortran program, we will specify the -assume nounderscore option of the ifort compiler (or -fno‑underscoring option if gfortran compiler) to prevent the compiler from adding the _ character during the generation of external references corresponding to C function calls. Of course, if the references accept this character as a suffix, this option should not be specified.
  • As Fortran generates the external references in lower-case letters, this must be respected when making calls in C.

Example of call from C

appelf.c
#include <stdio.h>
int main ()
{
  int   lg_chaine  = 0;
  float reel       = 0.0;
  char  chaine[]   = "chaîne_C                      ";
 
  lg_chaine = strlen(chaine);
  concat( &lg_chaine, &reel, chaine);
 
  printf("chaîne finale                = %sn", chaine);
  printf("longueur de la chaîne finale = %dn", lg_chaine);
  printf("réel passé par adresse       = %fn", reel);
 
  return 0;
}

Definition exemple with Fortran 2003/2008

concat.f90
module m
  use ISO_C_BINDING, only : C_CHAR, C_INT, C_FLOAT
contains
  SUBROUTINE concatenation( lg_chaine, reel, tab_car) bind(C,name='concat')
    INTEGER(kind=C_INT)                          :: lg_chaine
    REAL(kind=C_FLOAT)                           :: reel
    CHARACTER(kind=C_CHAR), dimension(lg_chaine) :: tab_car
    !
    CHARACTER(kind=C_CHAR,len=lg_chaine)         :: chaine
    !write( chaine, '(*(a))' ) tab_car ! Format => Fortran 2008
    ! ou bien
    do i=1,lg_chaine
      chaine(i:i) = tab_car(i)
    end do
    !
    chaine    = TRIM(chaine)//' et chaîne_Fortran'
    lg_chaine = LEN_TRIM(chaine)
    reel      = 100.0
  END SUBROUTINE concatenation
end module m
$ icc -c appelf.c
$ ifort -c concat.f90
$ ifort -nofor-main appelf.o concat.o -o appelc.exe
$ appelc.exe

chaîne finale                = chaîne_C et chaîne_Fortran
longueur de la chaîne finale = 26
réel passé par adresse       = 100.000000

Definition exemple with Fortran 90/95

concat.f90
SUBROUTINE concat( lg_chaine, reel, chaine)
  INTEGER,                  INTENT(INOUT) :: lg_chaine
  REAL,                     INTENT(INOUT) :: reel
  CHARACTER(LEN=lg_chaine), INTENT(INOUT) :: chaine
  chaine    = TRIM(chaine)//' et chaîne_Fortran'
  lg_chaine = LEN_TRIM(chaine)
  reel      = 100.0
END SUBROUTINE concat
$ icc -c appelf.c
$ ifort -c -assume nounderscore concat.f90
$ ifort -nofor-main appelf.o concat.o -o appelc.exe
$ appelc.exe

chaîne finale                = chaîne_C et chaîne_Fortran
longueur de la chaîne finale = 26
réel passé par adresse       = 100.000000