Turing : Calling C functions from Fortran

Some useful recommendations:

  1. The Fortran 2003 standard has defined a way of interfacing the Fortran procedures with fonctions written in C. We recommend this solution because it both ensures portability and allows any Fortran data types to interoperate with language C types. (For more complete information, refer to Chapter 9 of the Fortran 2003 course: Interoperability between C and Fortran).
  2. Parameter passing in Fortran is done by address, whereas in C it is done by value.
  3. The Fortran character strings passed as argument must be terminated by the character achar(0).

Be aware that if you don't choose the solution of interoperability proposed by Fortran 2003, you will have the following restrictions:

  1. Only the C functions whose arguments are pointers can be interfaced.
  2. The C pointers being coded on 64 bits, a Fortran procedure which wishes to use a value such as this must do it via an integer variable of the same size.
  3. In the case where the function C names are suffixed by the character "_", it will be necessary to specify the option -qextname of the compiler xlf90 in order for this character to be added during the generation of external references corresponding to the C function calls.

Example of C functions

fonctions.c
#include <string.h>
 
void fonction( char  *chaine,
               int   *entier,
	       float *reel )
{
   strcat( chaine, " et chaine_c" );
  *entier = strlen( chaine );
  *reel   = 100.0;
}
 
typedef struct cel
{
  float r;
  int   n;
} Cellule;
 
/*
 *  Function returning the address of 
 *  an object of type Cellule
 */
Cellule *creation_cel( float *r,
                       int   *n )
{
  Cellule *c = malloc( sizeof(Cellule) );
 
  c->r = *r; c->n = *n;
 
  return c;
}
 
void modif_cel( Cellule **c,
                float    *r,
                int      *n )
{
  (*c)->r = *r; (*c)->n = *n;
 
  return;
}
 
void imp_cel( Cellule **c )
{
  printf( "Cellule : %f, %d\n", (*c)->r, (*c)->n );
 
  return;
}
 
void libere_cel( Cellule **c )
{
  free( *c );
 
  return;
}

Example of a call in Fortran 2003/2008

appelc.f90
module appelC
  use ISO_C_BINDING
  type, bind(C) :: cel
    real(kind=C_FLOAT)  :: r
    integer(kind=C_INT) :: n
  end type cel
  interface
    subroutine sp(chaine, lg_chaine, reel ) bind(C,name='fonction')
      import C_CHAR,C_INT,C_FLOAT
      character(kind=C_CHAR),dimension(*) :: chaine
      integer(kind=C_INT)                 :: lg_chaine
      real(kind=C_FLOAT)                  :: reel
    end subroutine sp
    !
    type(C_PTR) function creat( r, n ) bind(C,name='creation_cel')
      import C_INT,C_FLOAT,C_PTR
      real(kind=C_FLOAT)  :: r
      integer(kind=C_INT) :: n
    end function creat
    !
    subroutine modif( cel, r, n ) bind(C,name='modif_cel')
      import C_INT,C_FLOAT,C_PTR
      type(C_PTR)         :: cel
      real(kind=C_FLOAT)  :: r
      integer(kind=C_INT) :: n
    end subroutine modif
    !
    subroutine imp( cel ) bind(C,name='imp_cel')
      import C_PTR
      type(C_PTR) :: cel
    end subroutine imp
    !
    subroutine libere( cel ) bind(C,name='libere_cel')
      import C_PTR
      type(C_PTR) :: cel
    end subroutine libere
  end interface
end module appelC
!
PROGRAM appel_c
  use appelC
  IMPLICIT NONE
  INTEGER            :: lg_chaine = 0
  REAL               :: reel      = 0.0
  CHARACTER(len=40)  :: chaine    = 'chaîne_Fortran'//C_NULL_CHAR
  !
  ! The following type is necessary for using the C address.
  type(C_PTR)        :: cellule
  type(cel), pointer :: p_cel
  CALL sp( chaine, lg_chaine, reel )
  ! Suppression of the character "C_NULL_CHAR"
  chaine = chaine(1:lg_chaine)
  PRINT '(2a)'    ,'chaîne finale                = ', chaine
  PRINT '(a,i0)'  ,'longueur de la chaîne finale = ', lg_chaine
  PRINT '(a,f0.4)','réel passé par adresse       = ', reel
  cellule = creat( acos(-1.), 1756 )
  call C_F_POINTER( CPTR=cellule, FPTR=p_cel )
  call imp( cellule )
  call modif( cellule, exp(1.), 1791 )
  call imp( cellule )
  call libere( cellule )
END PROGRAM appel_c
$ xlc -c fonctions.c
$ xlf90 appelc.f90 fonctions.o -o appelc.exe
$ ./appelc.exe
chaîne finale                = chaîne_Fortran et chaine_c
longueur de la chaîne finale = 26
réel passé par adresse       = 100.0000
Cellule : 3.141593, 1756
Cellule : 2.718282, 1791

Example of a call in Fortran 90/95

appelc.f90
PROGRAM appel_c
  IMPLICIT NONE
  INTEGER           ::  lg_chaine = 0
  REAL              ::  reel      = 0.0
  CHARACTER(len=40) ::  chaine    = 'chaîne_Fortran'//achar(0)
  !
  ! The following type is necessary for using the C address.
  INTEGER(kind=8)   ::  creation_cel, cellule
  CALL fonction( chaine, lg_chaine, reel )
  ! Suppression of the character "achar(0)"
  chaine = chaine(1:lg_chaine)
  PRINT '(2a)'    ,'chaîne finale                = ', chaine
  PRINT '(a,i0)'  ,'longueur de la chaîne finale = ', lg_chaine
  PRINT '(a,f0.4)','réel passé par adresse       = ', reel
  cellule = creation_cel( acos(-1.), 1756 )
  call imp_cel( cellule )
  call modif_cel ( cellule, exp(1.), 1791 )
  call imp_cel( cellule )
  call libere_cel( cellule )
END PROGRAM appel_c
$ xlc -c fonctions.c
$ xlf90 appelc.f90 fonctions.o -o appelc.exe
$ ./appelc.exe
chaîne finale                = chaîne_Fortran et chaine_c
longueur de la chaîne finale = 26
réel passé par adresse       = 100.0000
Cellule : 3.141593, 1756
Cellule : 2.718282, 1791