Jean Zay : appel des fonctions Fortran à partir de C
Quelques recommandations utiles :
- 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;
- le passage des paramètres en Fortran s'effectue par adresse, alors qu'en C la transmission se fait par valeur ;
- 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 fonctionmain
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 :
- lorsque C active une procédure Fortran, les arguments fournis lors de l'appel doivent être des adresses d'objets de type de base ;
- lors de la compilation du programme Fortran on précisera l'option
-assume nounderscore
du compilateurifort
(-fno-underscoring
s'il s'agit degfortran
) 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 ; - 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