Table des matières
Jean Zay: Calling C functions from Fortran
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.
- The Fortran character strings passed as arguments 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:
- Only the C functions whose arguments are pointers can be interfaced.
- C pointers are coded on 64 bits and a Fortran procedure wanting to use a C pointer must do it via an integer variable of the same size.
- During compilation of the Fortran program, we will specify the
-assume nounderscore
option of theifort
compiler (or-fno-underscoring
option ifgfortran
) in order to prevent the compiler from adding the_
character during the generation of external references corresponding to C function calls. Of course, this option should not be specified if the references accept this character as a suffix.
Example of C functions
- functions.c
#include <string.h> void fonction( char *chaine, int *entier, float *reel ) { strcat( chaine, " et chaine_c" ); *entier = strlen( chaine ); *reel = 100.0; }thos typedef struct cel { float r; int n; } Cellule; /* * Function returning the address of an object * of type cell */ 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 from Fortran 2003/2008
- appelc.f90
module appelC use ISO_C_BINDING, only : C_CHAR, C_INT, C_FLOAT, C_PTR 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 ISO_C_BINDING, only : C_PTR, C_F_POINTER, C_NULL_CHAR 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 ) ! Deletion 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
$ icc -c fonctions.c $ ifort 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 from 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 ) ! Deletion 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
$ icc -c fonctions.c $ ifort -assume nounderscore 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