[fortran 77] tableaux locaux

Résolu/Fermé
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 - 24 juil. 2009 à 12:32
cchristian Messages postés 921 Date d'inscription lundi 21 janvier 2008 Statut Membre Dernière intervention 6 mars 2012 - 30 juil. 2009 à 00:44
Bonjour,
j'ai un problème assez théorique.
j'ai un fichier fortran contenant une subroutine contenant des tableaux locaux dimensionnés avec un entier pouvant varier au cours du programme.
Théoriquement, ceci est interdit en Fortran 77, mais gcc/gfortran le compile sans souci.
Ma question est alors : que fait le compilateur dans ce cas là ?
Il dimensionne le tableau à la bonne taille à chaque appel de la subroutine, ou il fait n'imoprte quoi et fait un dépassement de tableau ?

11 réponses

cchristian Messages postés 921 Date d'inscription lundi 21 janvier 2008 Statut Membre Dernière intervention 6 mars 2012 131
25 juil. 2009 à 13:05
Bonjour,

Peux-tu poster les morceaux de codes où tu décris: le tableau, la variable qui le dimension et un cas d'utilisation du tableau.
0
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
25 juil. 2009 à 20:22
par exemple (exemple théorique, simplifié) :
subroutine TEST(A,B)
IMPLICITE REAL*8 (A-H,O-Z)
COMMON DONNES/NBTAB/
DIMENSION A(*),B(*)
DIMENSION TABDYN(NBTAB)
DO 20 I=1,NBTAB
TABDYN(I)=a(i)+b(i)
20 continue
A=TABDYN(3)
B=TABDYN(5)
RETURN


Voilà en simplifier ce qui est fait.
Là, je ne suis pas en mesure de tester le code, mais théoriquement, le tableau étant alloué dynamiquement, le comportement n'est pas régi par le F77. Donc que fait le code ??
Si besoin, je tenterai de faire un autre petit démonstrateur si tu veux.
Merci.
0
cchristian Messages postés 921 Date d'inscription lundi 21 janvier 2008 Statut Membre Dernière intervention 6 mars 2012 131
26 juil. 2009 à 01:33
ANNULATION DE CE MESSAGE A 2h02 PAR MOI-MÊME: REPONSE INCOMPLETE
0
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
27 juil. 2009 à 09:26
Heu ?
Toute piste est la bien venu.
Dans le message précédent, j'ai oublié de préciser que le common est initialisé dans un fichier C.
Voici un exemple complet :
main.c :
struct commun
{
   int nbtab;
};
void test(void);
extern  struct commun donnee;
int main()
{
    donnee.nbtab=10;
    int i;
    for(i=0;i<100;++i)
        test();
    return 0;
}

test.f :
      subroutine test()
      integer nbtab,i
      common /donnee/nbtab
      real*8 tab
      dimension tab(nbtab)
      do 10 i=1,nbtab
          tab(i)=tab(i)+1.D0
10    continue
      return
      end
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
cchristian Messages postés 921 Date d'inscription lundi 21 janvier 2008 Statut Membre Dernière intervention 6 mars 2012 131
27 juil. 2009 à 18:55
Bonjour,

Voici quelques remarques faites à partir de ton 1er exemple quelque peu remanié:

C                    Cinématique de fonctionnement:
C     On déclare 2 tableaux S_A et S_B de 20 postes chacun. Après une
C      initialisation à la valeur 1 de leur 12 premiers postes, ces 2 
C      tableaux sont passés à la subroutine TEST.

C      La première fois en délimitant le nombre de postes S_NBTAB avec 
C      une valeur (10) inférieure à la taille des tableaux:
C  Résultats d'exécution (1er appel subroutine):
C A ( 1) :   1.+B ( 1) :   1. = TABDYN( 1) :   2.
C A ( 2) :   1.+B ( 2) :   1. = TABDYN( 2) :   2.
C A ( 3) :   1.+B ( 3) :   1. = TABDYN( 3) :   2.
C A ( 4) :   1.+B ( 4) :   1. = TABDYN( 4) :   2.
C A ( 5) :   1.+B ( 5) :   1. = TABDYN( 5) :   2.
C A ( 6) :   1.+B ( 6) :   1. = TABDYN( 6) :   2.
C A ( 7) :   1.+B ( 7) :   1. = TABDYN( 7) :   2.
C A ( 8) :   1.+B ( 8) :   1. = TABDYN( 8) :   2.
C A ( 9) :   1.+B ( 9) :   1. = TABDYN( 9) :   2.
C A ( 10) :   1.+B ( 10) :   1. = TABDYN( 10) :   2.
C      Le résultat est évidemment cohérent.  

C      la seconde fois S_NBTAB est forcé avec une valeur (25) supérieure 
C      à la taille des tableaux S_A et S_B (20). Les postes 13 à 20
C      sont renseignés avec la valeur 8 pour le tableau S_A et avec la 
C      valeur 9 pour le tableau S_B avant l'appel à la subroutine TEST.
C      Les postes 21 à 25 de TABDYN sont renseignés avec la logique du 
C      sous-programme TEST, chacun à la valeur 999, 
C  Résultats d'exécution (2ème appel subroutine):
C A ( 1) :   1.+B ( 1) :   1. = TABDYN( 1) :   2.
C A ( 2) :   1.+B ( 2) :   1. = TABDYN( 2) :   2.
C A ( 3) :   1.+B ( 3) :   1. = TABDYN( 3) :   2.
C A ( 4) :   1.+B ( 4) :   1. = TABDYN( 4) :   2.
C A ( 5) :   1.+B ( 5) :   1. = TABDYN( 5) :   2.
C A ( 6) :   1.+B ( 6) :   1. = TABDYN( 6) :   2.
C A ( 7) :   1.+B ( 7) :   1. = TABDYN( 7) :   2.
C A ( 8) :   1.+B ( 8) :   1. = TABDYN( 8) :   2.
C A ( 9) :   1.+B ( 9) :   1. = TABDYN( 9) :   2.
C A ( 10) :   1.+B ( 10) :   1. = TABDYN( 10) :   2.
C A ( 11) :   1.+B ( 11) :   1. = TABDYN( 11) :   2.
C A ( 12) :   1.+B ( 12) :   1. = TABDYN( 12) :   2.
C A ( 13) :   8.+B ( 13) :   9. = TABDYN( 13) :   17.
C A ( 14) :   8.+B ( 14) :   9. = TABDYN( 14) :   17.
C A ( 15) :   8.+B ( 15) :   9. = TABDYN( 15) :   17.
C A ( 16) :   8.+B ( 16) :   9. = TABDYN( 16) :   17.
C A ( 17) :   8.+B ( 17) :   9. = TABDYN( 17) :   17.
C A ( 18) :   8.+B ( 18) :   9. = TABDYN( 18) :   17.
C A ( 19) :   8.+B ( 19) :   9. = TABDYN( 19) :   17.
C A ( 20) :   8.+B ( 20) :   9. = TABDYN( 20) :   17.
C  TABDYN( 21) :   999.
C  TABDYN( 22) :   999.
C  TABDYN( 23) :   999.
C  TABDYN( 24) :   999.
C  TABDYN( 25) :   999.
C      Le résultat est LUI AUSSI cohérentpour 25 postes de TABDYN.

C      Par contre si dans la subroutine TEST on tente de renseigner un
C      NBTAB + 1 => (25 + 1)ième poste le programme plante: 
C       DO 20       I  =  1,     NBTAB  + 1 ! Pour test de débordement.
C      le programme plante... C'EST NORMAL !

 
       PROGRAM  TEST0                                                                      
				 							     
       IMPLICIT NONE

       COMMON       /DONNES/  S_NBTAB           ! Variable de passation. 
       
       INTEGER      S_NBTAB                     ! Borne tableaux.
       INTEGER      K 
       
       DIMENSION    S_A (20) 
       REAL*8       S_A       
       DIMENSION    S_B (20) 
       REAL*8       S_B                                                 
                                              
        DATA (S_A (K), K = 1, 12, 1) / 12 * 1 / !12 postes des Tableaux
        DATA (S_B (K), K = 1, 12, 1) / 12 * 1 / !initialisés à 1.

       S_NBTAB      = 10                        
       CALL         TEST  (S_A, S_B)            ! 1er. Appel Subroutine.
                                           
       S_A    (13)  = 8      
       S_B    (13)  = 9      
       S_A    (14)  = 8      
       S_B    (14)  = 9      
       S_A    (15)  = 8      
       S_B    (15)  = 9      
       S_A    (16)  = 8      
       S_B    (16)  = 9      
       S_A    (17)  = 8      
       S_B    (17)  = 9      
       S_A    (18)  = 8      
       S_B    (18)  = 9      
       S_A    (19)  = 8      
       S_B    (19)  = 9      
       S_A    (20)  = 8      
       S_B    (20)  = 9     
       
       S_NBTAB      = 25     
       CALL         TEST  (S_A, S_B)            ! 2ème Appel Subroutine.

       END


       SUBROUTINE  TEST   (A, B) 

       IMPLICIT    REAL*8 (A-H, O-Z) 

       COMMON      /DONNES/     NBTAB

       DIMENSION   A(*),  B(*) 
       DIMENSION   TABDYN (NBTAB) 
       REAL*8      TABDYN     

C       DO 20       I  =  1,     NBTAB  + 1 ! Pour test de débordement.

       DO 20       I  =  1,     NBTAB,   1  
          IF (     I  >  20 )                                   THEN
              TABDYN  (I) =  999.00
          ELSE
              TABDYN  (I) =  A (I)  +  B (I) 
          END IF        
20     CONTINUE
 

       DO 30       I  =  1,     NBTAB,    1    ! Boucle pour contrôles.
          IF (     I  >  20 )                                   THEN
            PRINT *, ' TABDYN(', I,') : ', TABDYN(I)
          ELSE      
            PRINT *, 'A (', I,') : ', A (I), '+', 'B (', I,') : ', B (I) 
     S               ,' = TABDYN(', I,') : ', TABDYN(I)
          END IF  
30     CONTINUE 

       RETURN 
       END


Il semble par conséquent que l'aspect dynamique soit "géré" convenablement par le poduit Fortran 77 (Force 2.0) puisque le tableau TABDYN est chargé et exploré sans problème avec un nombres de postes différents à chaque appel de la subroutine dans laquelle il est décrit (la place mémoire doit donc être réservée dynamiquement). Sinon je ne vois pas très bien comment le compilateur pourrait s'en tirer.

Qu'en penses-tu ?
0
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
28 juil. 2009 à 08:20
Avec mon second test, j'ai exploré de grand tableaux (plus grand que ce qu'il pourrai mettre comme taille par défaut), sans souci.
Je pense en effet que le compilateur (gcc ou gfortran) gère correctement l'allocation dynamique du tableau. Je suis rassuré, le programme ne doit pas faire d'erreur. La réponse exact à ce problème doit se trouver dans le code assembleur généré, mais je n'ai rien compris à ce charabia :*)
En revanche, est-ce que cette façon de faire est présente dans le standard strict fortran 77 ?
Une de nos préoccupation est la portabilité, il faut donc se conformer au maximum au standard pour éviter les soucis.
Merci pour ton aide.
0
cchristian Messages postés 921 Date d'inscription lundi 21 janvier 2008 Statut Membre Dernière intervention 6 mars 2012 131
28 juil. 2009 à 14:17
Bonjour,

Je pense que tu trouveras des éléments de réponse supplémentaires sur ce site:
http://www.fortran.com/fortran/F77_std/rjcnf0001-sh-5.html#sh-5.5

plus particulèrement au paragraphe (situé au 3/4 de la page) :
5.5.1 Adjustable Arrays and Adjustable Dimensions.
0
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
28 juil. 2009 à 15:24
Merci pour le lien.
Par contre, je n'ai pas vraiment compris. De ce que j'ai compris, ça semble permis.
Pour l'instant, nous allons dimensionner nos tableaux avec une constante, en attendant de trouver une réponse clair.
0
cchristian Messages postés 921 Date d'inscription lundi 21 janvier 2008 Statut Membre Dernière intervention 6 mars 2012 131
29 juil. 2009 à 00:00
Bonsoir,

Pour l'instant, nous allons dimensionner nos tableaux avec une constante, en attendant de trouver une réponse clair

Ca semble plus sage en effet car il y a certaines choses qui m'étonnent comme par exemple, en modifiant le programme (lignes marquées ! <======= Modif), faire passer le tableau "TABDYN" de la partie Main à la subroutine. Le programme continue de fonctionner sans problème bien que S_TABDYN est décrit en Main de taille inférieure à son homologue TABDYN décrit dans la subroutine. Alors que la règle suivante :
The size of the adjustable array must be less than or equal to the size of the array that is its corresponding actual argument
est enoncée au paragraphe :
6.1.1.1 Adjustable Arrays de
http://www.helsinki.fi/atk/unix/dec_manuals/cf77au/olrm0121.htm

Par contre quand je compile et je lance une exécution du même programme avec l'IDE Silverfrost FTN95 il part en abend avec le message :
Runtime error from program:c:\docume~1\christ~1\mesdoc~1\b-fort~1.fil\test0.exe
Run-time Error
Attempt to call a routine with argument number three containing too few array elements

TEST - in file test0.f at line 101 [+00af]
TEST0 - in file test0.f at line 79 [+0066]

Ah ces compilateurs ! Le moins que l'on puisse dire, c'est que "ce n'est pas portable"

A noter que la version initiale de mon programme (hors <======= Modif) passe sans problème dans les deux environnements.

       PROGRAM  TEST0                                                                      
       IMPLICIT NONE

       COMMON       /DONNES/  S_NBTAB           ! Variable de passation. 
       
       INTEGER      S_NBTAB                     ! Borne tableaux.
       INTEGER      K 
       
       DIMENSION    S_A (20) 
       REAL*8       S_A       
       DIMENSION    S_B (20) 
       REAL*8       S_B                                                 

C       DIMENSION    S_TABDYN (1:1)              ! <======= Modif.  
C       REAL*8       S_TABDYN                    ! <======= Modif.
                                              
        DATA (S_A (K), K = 1, 12, 1) / 12 * 1 / !12 postes des Tableaux
        DATA (S_B (K), K = 1, 12, 1) / 12 * 1 / !initialisés à 1.

       S_NBTAB      = 10                        
       CALL         TEST  (S_A, S_B)
C       CALL         TEST  (S_A, S_B, S_TABDYN)  ! <======= Modif.
                                           
       S_A    (13)  = 8      
       S_B    (13)  = 9      
       S_A    (14)  = 8      
       S_B    (14)  = 9      
       S_A    (15)  = 8      
       S_B    (15)  = 9      
       S_A    (16)  = 8      
       S_B    (16)  = 9      
       S_A    (17)  = 8      
       S_B    (17)  = 9      
       S_A    (18)  = 8      
       S_B    (18)  = 9      
       S_A    (19)  = 8      
       S_B    (19)  = 9      
       S_A    (20)  = 8      
       S_B    (20)  = 9     
       
       S_NBTAB      = 25     
       CALL         TEST  (S_A, S_B)
C       CALL         TEST  (S_A, S_B, S_TABDYN ) ! <======= Modif.

       END


       SUBROUTINE  TEST   (A, B)
C       SUBROUTINE  TEST   (A, B,TABDYN)         ! <======= Modif.

       IMPLICIT    REAL*8 (A-H, O-Z) 

       COMMON      /DONNES/     NBTAB

       DIMENSION   A(*),  B(*) 
       DIMENSION   TABDYN (1:NBTAB) 
       REAL*8      TABDYN    

       DO 20       I  =  1,     NBTAB,   1  
          IF (     I  >  20 )                                   THEN
              TABDYN  (I) =  999.00
          ELSE
              TABDYN  (I) =  A (I)  +  B (I) 
          END IF        
20     CONTINUE
 

       DO 30       I  =  1,     NBTAB,    1    ! Boucle pour contrôles.
          IF (     I  >  20 )                                   THEN
            PRINT *, ' TABDYN(', I,') : ', TABDYN(I)
          ELSE      
            PRINT *, 'A (', I,') : ', A (I), '+', 'B (', I,') : ', B (I) 
     S               ,' = TABDYN(', I,') : ', TABDYN(I)
          END IF  
30     CONTINUE 

       RETURN 
       END
0
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
29 juil. 2009 à 07:58
Salut.
lorsque tu passe le tableau en argument, il est en effet étonnant qu'il n'y ait pas une erreur de segmentation. Je connait mieux le C, et j'ai déjà eu des cas en C, où l'écriture en dehors du tableau ne posait pas de souci. En fait, ce n'est pas parceque tu écris ou lit en dehors du tableau que tu génère une erreur de segmentation, il faut lire et écrire en dehors de la mémoire allouée au programme. Il est probable qu'avec un tableau plus grand ou aléatoirement, il plante.

C'est pas carré tout ça...
0
cchristian Messages postés 921 Date d'inscription lundi 21 janvier 2008 Statut Membre Dernière intervention 6 mars 2012 131
30 juil. 2009 à 00:44
Bonsoir,

J'ai fait passer NBTAB à 200000 et effectivement ça plante dans le cas passation du tableau TABDYN décrit en main alors que dans le cas passation de NBTAB et description du tableau en subroutine ça passe.
0