Table des matières
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 Fortranmain
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 theifort
compiler (or-fno‑underscoring
option ifgfortran
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