J'essaie de m'apprendre Fortran et je me suis amusé à lier plusieurs fichiers ensemble. Les exemples suivants, j'ai écrit des programmes dans un fichier, des fonctions dans un autre, et j'ai utilisé des blocs d'interface dans mon programme principal pour faire référence à la fonction externe.
Je testais la quantité d'informations nécessaires dans le bloc d'interface et je me suis rendu compte que je peut le supprimer entièrement.
Mon programme:
subroutine func(x,y) implicit none real :: x,y y = x**3 end subroutine func
Et le fichier de fonction:
function func(x) implicit none real :: x, func func = x**3 end function func
Je le compile ensuite en utilisant gfortran -o test test.f90 func.f90
et le code fonctionne comme prévu. Ma question est la suivante: pourquoi n'ai-je pas besoin d'inclure un bloc d'interface dans mon fichier programme? Est-ce simplement une question de bonne pratique, ou est-ce que définir func
comme une variable réelle sert de raccourci? Je suis sous Windows, ayant installé gfortran via minGW.
En tant que question secondaire / connexe, si j'utilise à la place un sous-programme:
program test implicit none real :: x, y, func x = 3 y = func(x) print *, y end program test
Et changez le ligne y = func (x)
à appel func (x, y)
alors le code fonctionnera correctement sans aucun bloc d'interface ni déclaration. Pourquoi est-ce?
3 Réponses :
Pourquoi n'ai-je pas besoin d'inclure un bloc d'interface dans mon fichier programme?
Depuis Fortran 90, la manière recommandée pour définir des fonctions et des sous-programmes réutilisables est d'utiliser des modules.
module func_m contains function func(x) implicit none real :: x, func func = x**3 end function func end module func_mEnsuite, écrivez
use func_m
dans le main programme, avantimplicite aucun
:gfortran -c func_m.f90
,gfortran -c test.f90
etgfortran -o test test. o func_m.o
.Lorsque vous utilisez des modules, le compilateur vérifiera le type des arguments des fonctions. Vous n'avez pas non plus besoin de déclarer
real :: func
car les déclarations sont extraites du module.Lorsque vous compilez comme un fichier objet "simple", le compilateur appellera simplement quelle que soit la fonction nommée
func
sans vérification, tant qu'une telle fonction est donnée dans un fichier objet.Le bloc d'interface est une sorte de "entre les deux". Dans votre cas, vous pouvez en ajouter un dans le fichier programme. Cela vous obligerait à suivre cette déclaration dans le programme. Mais cela n'empêchera pas la connexion à de mauvaises fonctions au moment de la liaison: il n'y a aucune garantie que l'interface est correcte. C'est surtout utile si vous devez appeler du code C ou FORTRAN 77 de quelqu'un d'autre, pour lequel vous ne pouvez pas utiliser de modules.
Et changez la ligne y = func (x) pour appeler func (x, y) alors le code sera fonctionne bien sans aucun bloc d'interface ni déclaration. Pourquoi est-ce?
Le problème d'interface est orthogonal au problème de fonction vs sous-programme.
La déclaration real :: func
dans le programme principal ici déclare que func
est une fonction avec un résultat réel (par défaut). Cette fonction a une interface dans le programme principal en conséquence, il est donc légitime de référencer cette fonction avec y = func (x)
.
Dans ce cas, l'interface est implicite . De cette façon, le programme principal sait exactement trois choses sur func
:
external
; La référence à la fonction est compatible avec cette connaissance. De plus, la façon dont vous faites référence à la fonction correspond précisément aux propriétés de la fonction elle-même.
De même, dans le cas du sous-programme, un call func (x, y)
indique exactement trois choses au programme principal, toujours avec l'interface implicite:
external
; Ces trois choses correspondent à nouveau à la définition du sous-programme, donc tout va bien.
En gros, vous n'avez donc pas besoin d'un bloc d'interface dans ces cas car les interfaces implicites sont assez bonnes.
Il y a des moments où une interface explicite est requise et dans la plupart (presque tous) cas une interface explicite est meilleure. Comme vous pouvez le voir dans d'autres questions et réponses, il existe généralement de meilleures façons de fournir une interface explicite que d'utiliser un bloc d'interface.
Dans certains cas, des blocs d'interface sont nécessaires. Par exemple si le sous-programme appelé utilise un pointeur, des tableaux de forme allouables ou supposés (cette liste n'est pas complète, voir le standard pour plus):
integer, pointer :: x(:,:) ! pointer attribute integer, allocatable :: x(:,:) ! pointer attribute integer :: a(:,:) ! assumed shape array
Le pointeur / attribuable a l'avantage que l'appelé le sous-programme peut l'allouer pour la fonction appelante. Les tableaux de formes supposées transfèrent automatiquement les dimensions vers le sous-programme appelé.
Si vous utilisez l'un de ces éléments, votre programme plantera sans interface explicite. La solution la plus simple est comme indiqué dans l'autre réponse: utilisez des modules pour que l'interface soit automatiquement correcte. Nous utilisons un script perl extrayant automatiquement les interfaces pour vérifier l'interface sans réécrire le code dans les modules (et éviter les longs temps de compilation jusqu'à ce que tous les compilateurs prennent en charge de manière fiable les sous-modules Fortran 2008 ...)
Même avec ceux-ci, les blocs d'interface ne sont toujours pas nécessaires.
les tableaux de formes supposées nécessitent une interface