Jean Zay : appel des fonctions Fortran à partir de C

Quelques recommandations utiles :

  1. la norme 2003 de Fortran a défini une manière d'interfacer des procédures Fortran avec des fonctions écrites en C. On recommande cette solution car elle a l'avantage d'une part d'assurer la portabilité et d'autre part de permettre la mise en relation de tout type Fortran avec ceux du langage C.\\Pour de plus amples informations, se reporter au chapitre 9 du cours Fortran 2003 : Interopérabilité entre entités C et Fortran;
  2. le passage des paramètres en Fortran s'effectue par adresse, alors qu'en C la transmission se fait par valeur ;
  3. il est recommandé de faire l'édition de liens avec le compilateur Fortran. S'il s'agit du compilateur ifort, l'option -nofor-main est nécessaire pour indiquer que la fonction main n'est pas celle de Fortran.

Sachez que si vous n'adoptez pas la solution proposée par Fortran 2003, vous vous exposez aux restrictions suivantes :

  1. lorsque C active une procédure Fortran, les arguments fournis lors de l'appel doivent être des adresses d'objets de type de base ;
  2. lors de la compilation du programme Fortran on précisera l'option -assume nounderscore du compilateur ifort (-fno-underscoring s'il s'agit de gfortran) afin que celui-ci n'ajoute pas le caractère _ lors de la génération des références externes correspondant aux appels effectués en C. Évidemment, si lors de ces appels ce caractère est indiqué en tant que suffixe, cette option ne devra pas être indiquée ;
  3. comme Fortran génère les références externes en minuscules, ceci devra être respecté lors des appels effectués en C.

Exemple d'appel 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;
}

Exemple de définition en 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

Exemple de définition en 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