Interopérabilité avec C
L’interopérabilité Fortran–C suppose évidemment que l’on ne manipule que des entités (variables, fonctions, concepts, …) communes aux deux langages, ce qui impose un certain nombre de restrictions et de contraintes.
Pour faciliter le travail du programmeur et améliorer la portabilité de son code, la norme Fortran 2003 fournit un certain nombre de nouveaux éléments syntaxiques nécessaires pour faciliter la définition d’entités interopérables qui seront ainsi connues et controlées comme telles a` l’étape de compilation Fortran.
L’acc`es (USE) au module ISO C BINDING permet l’interopérabilité avec C pour un certain nombre d’entités que nous allons passer en revue…
Note : l’interopérabilit´ Fortran–C est disponible avec le compilateur Fortran IBM depuis la version 9.1.0.
Entités de type intrinseques
Via des constantes symboliques définissant :
1. la valeur enti`ere du param`etre KIND des types/sous-types autorisés. Par exemple
Note : pour le type CHARACTER, C ne supportant que les variables de longueur 1 (gérées sous forme de tableaux), on pourra déclarer une chaˆıne sous la forme :
CHARACTER(kind=C_CHAR), dimension(*) :: chaine
Tableaux C
Un tableau Fortran est interopérable s’il est d’un type interopérable et de profil explicite ou de taille implicite.
De plus pour les tableaux multidimensionnés, l’ordre des indices doit ˆetre invers´. Ainsi les tableaux Fortran :
integer(kind=C_INT), dimension(18,3:7,*) :: t1
integer(kind=C_INT), dimension(18,3:7,100) :: t2
sont interopérables avec les tableaux ainsi déclarés en C :
int t1[][5][18]
int t2[100][5][18]
Variables globales C
Une variable externe C peut interopérer avec un bloc COMMON ou avec une variable déclarée dans un module Fortran. Par exemple :
module variables_C
use, intrinsic :: ISO_C_BINDING
integer(C_INT), bind(C) :: c_extern
integer(C_LONG) :: fort_var
BIND( C, NAME=’C_var’ ) :: fort_var
common/COM/ r, s
common/SINGLE/ t
real(kind=C_FLOAT) :: r, s, t
bind(C) :: /COM/, /SINGLE/
end module variables_C
Ces variables Fortran sont interopérables avec celles définies en C au niveau externe par :
int c_extern;
long C_var;
struct {float r, s;} com;
float single;
Remarques
☞ une variable globale Fortran doit avoir eté déclarée avec l’attribut BIND(C) pour pouvoir ˆetre mise en correspondance avec une variable externe C,
☞ si cet attribut a et´ spécifi´ sans le param`etre NAME, une référence externe est générée enti`erement en minuscules,
☞ si le param`etre NAME a et´ précisé, sa valeur correspond au nom de la référence externe générée, en respectant les minuscules et/ou majuscules employées.
Les pointeurs
Les pointeurs C, quels qu’ils soient, sont interopérables avec des pointeurs Fortran particuliers du type dériv´ semi-privé C PTR dont une composante privée contient l’adresse cachée d’une cible.
On retrouve l`a l’analogie avec le descripteur du pointeur Fortran qui est sous-jacent a` l’attribut POINTER. Le pointeur en Fortran est un concept abstrait et puissant n’autorisant pas (fiabilité oblige) la manipulation arithmétique directe de l’adresse qui reste cachée.
La nécessit´ de définir les pointeurs de type C PTR, souvent appelés pointeurs C par opposition aux pointeurs Fortran, se justifie en partie par le fait que contrairement a` ces derniers ils ne peuvent/doivent pas désigner une zone mémoire non contigu¨e. De plus, le type C PTR est utilisable dans un contexte d’interopérabilit´ avec tout type de pointeur C (typé ou non – void*).
Toutes les manipulations relatives aux pointeurs C se font via des opérateurs ou des procédures (méthodes ), ainsi :
☞ C LOC(X) fonction retournant un scalaire de type C PTR contenant l’adresse de la cible X (au sens de l’opération unaire &X selon la norme C) ; par exemple :
use ISO_C_BINDING
real(C _FLOAT), dimension(10), target :: X
type(C _PTR) :: buf
buf = C_LOC(X)
A noter que la cible X doit avoir l’attribut TARGET ; elle peut désigner aussi bien un scalaire, un tableau statique, un tableau dynamique alloué, ou mˆeme un pointeur associé a` un scalaire.
Nous verrons plus loin comment la fonction C LOC facilite l’interopérabilit´ avec des pointeurs C.
☞ C F POINTER(CPTR, FPTR [,SHAPE]) : convertit CPTR de type C PTR en un pointeur Fortran FPTR (SHAPE a` spécifier si la cible est un tableau) ;
☞ C ASSOCIATED(C PTR 1[, C CPTR 2]) vérifie que deux pointeurs C (de type C PTR) sont identiques ou que le premier est a` l’état nul.
Notes :
1. si l’interopérabilit´ concerne un pointeur de fonction (C function pointer type), on utilisera alors les entités équivalentes :
– type dériv´ semi-privé C FUNPTR,
– fonction C FUNLOC(X) retournant l’adresse C d’une procédure X dans un scalaire de type C FUNPTR,
– sous-programme C F PROCPOINTER(CPTR, FPTR) : convertit CPTR, un pointeur de procédure de type C FUNPTR, en un pointeur Fortran FPTR .
2. ces entités permettent l’interopérabilit´ des tableaux dynamiques : un tableau Fortran alloué peut ˆetre passé a` C et un tableau alloué en C peut ˆetre associé a` un pointeur Fortran (cf. exemple en fin de chapitre).
Fonctions C et procédures Fortran
Nouveautés syntaxiques Fortran :
☞ attribut VALUE pour les arguments muets scalaires. L’argument d’appel
correspondant n’est plus passé par référence (adresse), mais via une copie
`
temporaire dans le stack. A noter que la copie en retour n’est pas faite, ce qui est exclusif de intent(OUT/INOUT) !
☞ attribut BIND(C [,NAME=…]) obligatoire a` la définition d’une procédure Fortran interopérable (ou du bloc interface associé a` une fonction C dont le nom peut ˆetre spécifi´ avec le sous-param`etre NAME=).
L’interface de procédure Fortran est constituée des informations exploitables par Fortran pour définir et contrˆoler l’interopérabilit´ avec un prototype de fonction C. Selon les cas, elle est constituée de :
Fortran ⇒ C l’appel procédural de la fonction C et le bloc interface associé ;
C ⇒ Fortran la partie déclarative de la procédure Fortran appelée.
Quelques r`egles a` respecter :
☞ interface explicite et attribut BIND(C) obligatoire,
☞ arguments muets tous interopérables (non optionnels) et en cohérence avec ceux du prototype C,
☞ une fonction Fortran doit retourner un scalaire interopérable et un sous-programme doit correspondre a` un prototype C retournant le type void,
☞ un argument du prototype C de type pointeur peut ˆetre associé `a un argument muet Fortran classique sans l’attribut VALUE (cf. exemple suivant),
☞ un argument du prototype C qui n’est pas de type pointeur doit ˆetre associé `a un argument muet avec l’attribut VALUE (cf. exemple suivant).
Exemple de fonction C appelée depuis Fortran
Dans cet exemple, Fortran passe a` C deux arguments :
– un tableau passé classiquement par référence,
– une variable enti`ere passée par valeur.
Tout d’abord, voici la fonction C appelée et son prototype :
float C_Func( float *buf, int count )
{
float somme = 0. ;
for( int i=0; i<count; i++ ) somme += buf[i] ;
return somme ;
}
Ci-apr`es, voici :
☞ le bloc interface associé a` la fonction C (dans un module), ☞ le programme Fortran appelant,
☞ un schéma récapitulatif du passage des arguments.
module FTN_C
use, intrinsic :: ISO_C_BINDING
interface
function C_FUNC (array, N) BIND(C, NAME= »C_Func »)
import C_INT, C_FLOAT
implicit none
real(kind=C_FLOAT) :: C_FUNC
real(kind=C_FLOAT), dimension(*) :: array
integer(kind=C_INT), VALUE :: N
end function C_FUNC
end interface
end module FTN_C
program p1
use FTN_C
integer(kind=C_INT), parameter :: n = 18
real(C _FLOAT), dimension(n) :: tab
:: y
real(kind=C _FLOAT)
call random_number( tab )
y = C_FUNC ( array=tab, N=n )
print *, « Val. retournée par la fonction : « , y end program p1
1 – Meilleure int´egration a l’environnement syst`eme
2 – Interoperabilite avec C
2.1 – Entites de type intrinseques
2.2 – Tableaux C
2.3 – Variables globales C
2.4 – Les pointeurs
2.5 – Fonctions C et procedures Fortran
2.5.1 – Exemple de fonction C appelee depuis Fortran
2.5.2 – Exemple de procédure Fortran appelee depuis C
2.5.3 – Interop´erabilite entre pointeurs : le type C PTR
2.6 – Structures de donn´ees C
3 – Arithmetique IEEE et traitement des exceptions
3.1 – Standard IEEE-754
3.1.1 – Valeurs speciales
3.1.2 – Exceptions
3.1.3 – Mode d’arrondi
3.2 – Integration standard IEEE : modules intrinseques
3.3 – Fonctions d’interrogation
3.4 – Procedures de gestion du mode d’arrondi
3.5 – Gestion des exceptions
3.6 – Procedures de gestion des interruptions
3.7 – Procedures de gestion du contexte arithmetique
3.8 – Exemple complementaire sur les exceptions
3.9 – Modules intrinseques
3.9.1 – Module IEEE EXCEPTIONS
3.9.2 – Module IEEE ARITHMETIC
3.9.3 – Module IEEE FEATURES
3.10 – Documentations
4 – Nouveautes concernant les tableaux dynamiques
4.1 – Passage en argument de procedure
4.2 – Composante allouable d’un type derive
4.3 – Allocation d’un scalaire ALLOCATABLE
4.4 – Allocation/reallocation via l’affectation
4.5 – Sous-programme MOVE ALLOC de reallocation
5 – Nouveautés concernant les modules
5.1 – L’attribut PROTECTED
5.2 – L’instruction IMPORT du bloc interface
5.3 – USE et renommage d’operateurs
6 – Entrees-sorties
6.1 – Nouveaux parametres des instructions OPEN/READ/WRITE
6.2 – Entrees-sorties asynchrones
6.3 – Entrees-sorties en mode stream
6.4 – Traitement personnalise des objets de type derive
7 – Pointeurs
7.1 – Vocation (INTENT) des arguments muets pointeurs
7.2 – Association et reprofilage
7.3 – Pointeurs de proc´edures
7.3.1 – Pointeurs de proc´edure : interface implicite
7.3.2 – Pointeurs de proc´edure : interface explicite
8 – Nouveaut´es concernant les types derives
8.1 – Composante pointeur de proc´edure
8.2 – Param`etres d’un type d´eriv´e
8.3 – Constructeurs de structures
8.4 – Visibilit´e des composantes
8.5 – Extension d’un type d´eriv´e
9 – Programmation orientee objet
9.1 – Variable polymorphique
9.1.1 – Argument muet polymorphique
9.1.2 – Variable polymorphique : attribut POINTER, ALLOCATABLE
9.2 – Construction SELECT TYPE
9.3 – Pointeurs generiques
9.4 – Type effectif d’une variable polymorphique
9.5 – Procedures attach´ees `a un type (type-bound procedures)
9.6 – Heritage
9.7 – Type abstrait
10 – En conclusion