Recherche…


Types de variables implicites

Lorsque Fortran a été développé à l’origine, la mémoire était très coûteuse. Les variables et les noms de procédure peuvent comporter 6 caractères au maximum et les variables sont souvent implicitement saisies . Cela signifie que la première lettre du nom de la variable détermine son type.

  • les variables commençant par i, j, ..., n sont des integer
  • tout le reste (a, b, ..., h et o, p, ..., z) est real

Des programmes comme le suivant sont acceptables Fortran:

program badbadnotgood
  j = 4
  key = 5 ! only the first letter determines the type
  x = 3.142
  print*, "j = ", j, "key = ", key, "x = ", x
end program badbadnotgood

Vous pouvez même définir vos propres règles implicites avec la déclaration implicit :

! all variables are real by default 
implicit real (a-z)

ou

! variables starting with x, y, z are complex
! variables starting with c, s are character with length of 4 bytes
! and all other letters have their default implicit type
implicit complex (x,y,z), character*4 (c,s) 

Le typage implicite n'est plus considéré comme la meilleure pratique. Il est très facile de faire une erreur en utilisant le typage implicite, car les fautes de frappe peuvent passer inaperçues, par exemple

program oops
  real :: somelongandcomplicatedname

  ...

  call expensive_subroutine(somelongandcomplEcatedname)
end program oops

Ce programme se déroulera avec plaisir et fera la mauvaise chose.


Pour désactiver le typage implicite, l'instruction implicit none peut être utilisée.

program much_better
  implicit none
  integer :: j = 4
  real :: x = 3.142
  print*, "j = ", j, "x = ", x
end program much_better

Si nous avions utilisé implicit none dans le programme oops ci-dessus, le compilateur aurait remarqué immédiatement et produit une erreur.

Arithmétique si déclaration

Arithmétique if instruction permet d'utiliser trois branches en fonction du résultat d'une expression arithmétique

if (arith_expr) label1, label2, label3

Cette instruction if transfère le flux de contrôle à l'une des étiquettes d'un code. Si le résultat de arith_expr est négatif, label1 est impliqué, si le résultat est nul, label2 est utilisé et si le résultat est positif, la dernière label3 est appliquée. if arithmétique requiert les trois étiquettes mais permet de réutiliser les étiquettes, cette instruction peut être simplifiée en deux branches if .

Exemples:

if (N * N - N / 2) 130, 140, 130

if (X) 100, 110, 120

Maintenant, cette fonctionnalité est obsolète avec la même fonctionnalité offerte par la construction if et if-else . Par exemple, le fragment

    if (X) 100, 110, 120
100 print*, "Negative"
    goto 200
110 print*, "Zero"
    goto 200
120 print*, "Positive"
200 continue

peut être écrit comme la construction if-else

if (X<0) then
  print*, "Negative"
else if (X==0) then
  print*, "Zero"
else
  print*, "Positive"
end if

Un remplacement de déclaration if pour

    if (X) 100, 100, 200
100 print *, "Negative or zero"
200 continue

peut être

if (X<=0) print*, "Negative or zero"

Constructions DO non bloquantes

Le non-bloc do construire ressemble

    integer i
    do 100, i=1, 5
100 print *, i

C'est-à-dire que l'instruction de terminaison étiquetée n'est pas une instruction continue . Il y a diverses restrictions sur l'instruction qui peut être utilisée comme instruction de terminaison et le tout est généralement très déroutant.

Une telle construction non-bloc peut être réécrite sous forme de bloc comme

    integer i
    do 100 i=1,5
      print *, i
100 continue

ou mieux, en utilisant une déclaration de end do terminaison,

integer i
do i=1,5
  print *, i
end do

Retour alternatif

Le retour alternatif est une fonction permettant de contrôler le flux d'exécution à la sortie d'un sous-programme. Il est souvent utilisé comme une forme de gestion des erreurs:

real x

call sub(x, 1, *100, *200)
print*, "Success:", x
stop

100 print*, "Negative input value"
stop

200 print*, "Input value too large"
stop

end

subroutine sub(x, i, *, *)
  real, intent(out) :: x
  integer, intent(in) :: i
  if (i<0) return 1
  if (i>10) return 2
  x = i
end subroutine

Le retour alternatif est marqué par les arguments * dans la liste d'arguments factices de la sous-routine.

Dans la déclaration d' call ci-dessus *100 et *200 réfèrent aux déclarations étiquetées 100 et 200 respectivement.

Dans la sous-routine elle-même, les instructions de return correspondant à une déclaration alternative ont un numéro. Ce nombre n'est pas une valeur de retour, mais indique l'étiquette fournie à laquelle l'exécution est transmise lors du retour. Dans ce cas, return 1 transmet l'exécution à l'instruction libellée 100 et return 2 passe l'exécution à l'instruction intitulée 200 . Une instruction de return sans ornement, ou l'exécution d'une exécution de sous-routine sans instruction de return , passe l'exécution immédiatement après l'instruction d'appel.

La syntaxe de retour alternative est très différente des autres formes d'association d'arguments et la fonctionnalité introduit le contrôle de flux contrairement aux goûts modernes. Un contrôle de flux plus agréable peut être géré avec le retour d'un code entier "status".

real x
integer status

call sub(x, 1, status)
select case (status)
case (0)
  print*, "Success:", x
case (1)
  print*, "Negative input value"
case (2)
  print*, "Input value too large"
end select

end

subroutine sub(x, i, status)
  real, intent(out) :: x
  integer, intent(in) :: i
  integer, intent(out) :: status

  status = 0

  if (i<0) then
    status = 1
  else if (i>10)
    status = 2
  else
    x = i
  end if

end subroutine

Formulaire source fixe

Fortran était à l'origine conçu pour un format de format fixe basé sur une carte perforée de 80 colonnes:

entrer la description de l'image ici

Oui: il s'agit d'une ligne du code de l'auteur

Celles-ci ont été créées sur une machine à perforer les cartes, comme ceci:

entrer la description de l'image ici

Les images sont des photographies originales de l'auteur

Le format, comme indiqué sur la carte illustrée illustrée, comportait les cinq premières colonnes réservées aux étiquettes de relevé. La première colonne a été utilisée pour désigner les commentaires par une lettre C. La sixième colonne a été utilisée pour désigner une suite d'instruction (en insérant un caractère autre qu'un zéro 0). Les 8 dernières colonnes ont été utilisées pour l'identification et le séquencement des cartes, ce qui était très utile si vous jetiez votre jeu de cartes par terre! Le codage des caractères pour les cartes perforées ne comportait qu'un ensemble limité de caractères et était uniquement en majuscules. En conséquence, les programmes Fortran ressemblaient à ceci:

       DIMENSION A(10)                                                    00000001
C THIS IS A COMMENT STATEMENT TO EXPLAIN THIS EXAMPLE PROGRAM             00000002
       WRITE (6,100)                                                      00000003
 100   FORMAT(169HTHIS IS A RATHER LONG STRING BEING OUTPUT WHICH GOES OVE00000004
      1R MORE THAN ONE LINE, AND USES THE STATEMENT CONTINUATION MARKER IN00000005
      2COLUMN 6, AND ALSO USES HOLLERITH STRING FORMAT)                   00000006
       STOP                                                               00000007
       END                                                                00000008

Le caractère d'espace a également été ignoré partout, sauf dans une constante de caractère Hollerith (comme indiqué ci-dessus). Cela signifiait que des espaces pouvaient apparaître à l'intérieur des mots réservés et des constantes, ou manquer complètement. Cela a eu l'effet secondaire de certaines déclarations plutôt trompeuses telles que:

       DO 1 I = 1.0

est une affectation à la variable DO1I alors que:

       DO1I = 1,0 

est en fait une boucle DO sur la variable I


Fortran moderne n'a pas besoin maintenant de cette forme fixe d'entrée et permet la forme libre en utilisant n'importe quelle colonne. Les commentaires sont maintenant indiqués par un ! qui peut également être ajouté à une ligne de relevé. Les espaces ne sont plus autorisés nulle part et doivent être utilisés comme séparateurs, comme dans la plupart des autres langues. Le programme ci-dessus pourrait être écrit dans Fortran moderne comme:

! This is a comment statement to explain this example program
Print *,"THIS IS A RATHER LONG STRING BEING OUTPUT WHICH no longer GOES OVER MORE THAN ONE LINE, AND does not need to USE THE STATEMENT CONTINUATION MARKER IN COLUMN 6, or the HOLLERITH STRING FORMAT"

Bien que l’ancienne suite ne soit plus utilisée, l’exemple ci-dessus montre que des déclarations très longues se produiront toujours. Le Fortran moderne utilise un symbole & à la fin et au début de la suite. Par exemple, nous pourrions écrire ce qui précède sous une forme plus lisible:

! This is a comment statement to explain this example program
Print *,"THIS IS A RATHER LONG STRING BEING OUTPUT WHICH still &
         &GOES OVER MORE THAN ONE LINE, AND does need to USE THE STATEMENT &
         &CONTINUATION notation"

Blocs communs

Dans les premières formes de Fortran, le seul mécanisme permettant de créer un stockage de variables global visible à partir de sous-programmes et de fonctions consiste à utiliser le mécanisme de bloc COMMON . Cela permettait aux séquences de variables d'être des noms et partagées en commun.

En plus des blocs communs nommés, il peut également y avoir un bloc commun vide (sans nom).

Un bloc commun vide pourrait être déclaré comme

common i, j

alors que les variables bloc nommées pourraient être déclarées comme

common /variables/ i, j

Comme exemple complet, nous pourrions imaginer un magasin de tas qui est utilisé par les routines qui peuvent ajouter et supprimer des valeurs:

       PROGRAM STACKING
       COMMON /HEAP/ ICOUNT, ISTACK(1023)
       ICOUNT = 0
       READ *, IVAL
       CALL PUSH(IVAL)
       CALL POP(IVAL)
       END

       SUBROUTINE PUSH(IVAL)
       COMMON /HEAP/ ICOUNT, ISTACK(1023)
       ICOUNT = ICOUNT + 1
       ISTACK(ICOUNT) = IVAL
       RETURN
       END

       SUBROUTINE POP(IVAL)
       COMMON /HEAP/ ICOUNT, ISTACK(1023)
       IVAL = ISTACK(ICOUNT)
       ICOUNT = ICOUNT - 1
       RETURN
       END

Les instructions communes peuvent être utilisées pour déclarer implicitement le type d'une variable et spécifier l'attribut de dimension . Ce comportement seul est souvent une source de confusion suffisante. De plus, l'association de stockage implicite et les exigences pour des définitions répétées entre les unités de programme rendent l'utilisation des blocs communs sujettes aux erreurs.

Enfin, les blocs communs sont très restreints dans les objets qu’ils contiennent. Par exemple, un tableau dans un bloc commun doit être de taille explicite; les objets attribuables peuvent ne pas se produire; les types dérivés ne doivent pas avoir d'initialisation par défaut.

Dans Fortran moderne, ce partage de variables peut être géré par l'utilisation de modules . L'exemple ci-dessus peut être écrit comme suit:

module heap
  implicit none
  ! In Fortran 2008 all module variables are implicitly saved
  integer, save :: count = 0
  integer, save :: stack(1023)
end module heap

program stacking
  implicit none
  integer val
  read *, val
  call push(val)
  call pop(val)

contains
  subroutine push(val)
    use heap, only : count, stack
    integer val
    count = count + 1
    stack(count) = val
  end subroutine push

  subroutine pop(val)
    use heap, only : count, stack
    integer val
    val = stack(count)
    count = count - 1
  end subroutine pop
end program stacking

Les blocs communs nommés et vides ont des comportements légèrement différents. À noter:

  • les objets des blocs communs nommés peuvent être définis initialement; les objets en blanc communs ne doivent pas être
  • les objets dans les blocs communs vides se comportent comme si le bloc commun avait l'attribut save ; les objets dans des blocs communs nommés sans l'attribut save peuvent ne plus être définis lorsque le bloc ne fait pas partie d'une unité de programme active

Ce dernier point peut être opposé au comportement des variables de module dans le code moderne. Toutes les variables de module dans Fortran 2008 sont implicitement enregistrées et ne deviennent pas indéfinies lorsque le module est hors de portée. Avant Fortran 2008, les variables de module, comme les variables dans les blocs communs nommés, deviendraient également indéfinies lorsque le module serait hors de portée.

GOTO attribué

GOTO assigné utilise une variable entière à laquelle une étiquette est affectée à l'aide de l'instruction ASSIGN.

100 CONTINUE

...

ASSIGN 100 TO ILABEL

...


GOTO ILABEL

Assigné GOTO est obsolète dans Fortran 90 et supprimé dans Fortran 95 et versions ultérieures. Il peut être évité dans le code moderne en utilisant des procédures, des procédures internes, des pointeurs de procédure et d’autres fonctionnalités.

GOTO calculé

GOTO calculé permet le branchement du programme en fonction de la valeur d'une expression entière.

GOTO (label_1, label_2,... label_n) scalar-integer-expression

Si scalar-integer-expression est égal à 1, le programme continue à l'étiquette d'étiquette label_1 , s'il est égal à 2, il passe à label_2 et ainsi de suite. Si elle est inférieure à 1 ou plus grand que n programme se poursuit sur la ligne suivante.

Exemple:

ivar = 2

...

GOTO (10, 20, 30, 40) ivar

sautera à l'étiquette d'étiquette 20.

Cette forme de goto est obsolète dans Fortran 95 et les versions ultérieures, étant remplacée par la construction de select case sélectifs.

Spécificateurs de format assignés

Avant Fortran 95, il était possible d'utiliser des formats assignés pour l'entrée ou la sortie. Considérer

integer i, fmt
read *, i

assign 100 to fmt
if (i<100000) assign 200 to fmt

print fmt, i

100 format ("This is a big number", I10)
200 format ("This is a small number", I6)

end

L'instruction assign assigne une étiquette à une variable entière. Cette variable entière est utilisée ultérieurement comme spécificateur de format dans l'instruction print .

Une telle attribution de spécificateur de format a été supprimée dans Fortran 95. Au lieu de cela, un code plus moderne peut utiliser une autre forme de contrôle de flux d'exécution.

integer i
read *, i

if (i<100000) then
  print 100, i
else
  print 200, i
end if

100 format ("This is a big number", I10)
200 format ("This is a small number", I6)

end

ou une variable de caractère peut être utilisée comme spécificateur de format

character(29), target :: big_fmt='("This is a big number", I10)'
character(30), target :: small_fmt='("This is a small number", I6)'
character(:), pointer :: fmt

integer i
read *, i

fmt=>big_fmt
if (i<100000) fmt=>small_fmt

print fmt, i

end

Fonctions de déclaration

Considérez le programme

implicit none
integer f, i
f(i)=i

print *, f(1)
end

Ici f est une fonction de déclaration. Il a un type de résultat entier, prenant un argument factice entier. 1

Une telle fonction d'instruction existe dans le cadre dans lequel elle est définie. En particulier, il a accès aux variables et aux constantes nommées accessibles dans cette étendue.

Cependant, les fonctions d'instruction sont soumises à de nombreuses restrictions et peuvent être source de confusion (en regardant un regard décontracté comme une instruction d'affectation d'éléments de tableau). Les restrictions importantes sont les suivantes:

  • le résultat de la fonction et les arguments factices doivent être scalaires
  • les arguments factices ont la même portée que la fonction
  • les fonctions d'instruction n'ont pas de variables locales
  • les fonctions d'instruction ne peuvent pas être passées comme arguments réels

Les principaux avantages des fonctions de relevé sont répétés par les fonctions internes

implicit none

print *, f(1)

contains

  integer function f(i)
    integer i
    f = i
  end function

end

Les fonctions internes ne sont pas soumises aux restrictions mentionnées ci-dessus, mais il est peut-être utile de noter qu’un sous-programme interne ne peut contenir d’autres sous-programmes internes (mais il peut contenir une fonction de relevé).

Les fonctions internes ont leur propre portée mais disposent également d'une association hôte.


1 Dans les vrais anciens exemples de code, il ne serait pas inhabituel de voir implicitement les arguments factices d'une fonction d'instruction, même si le résultat a un type explicite.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow