[fortran 77] tableaux locaux

Résolu
Char Snipeur Messages postés 10112 Date d'inscription   Statut Contributeur Dernière intervention   -  
cchristian Messages postés 928 Statut Membre -
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 ?
--
Salutation ! (il faut bien que vous compreniez que j'ai TOUJOURS raison)
Char Snipeur
Configuration: AMD Atlhon XP 2400+
1Go DDRAM 2700
CM : ABIT AN7
Radeon Asus 9600SE
OS : win XP pack1; Mandrake 10.0

11 réponses

  1. cchristian Messages postés 928 Statut Membre 131
     
    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
  2. Char Snipeur Messages postés 10112 Date d'inscription   Statut Contributeur Dernière intervention   1 331
     
    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
  3. cchristian Messages postés 928 Statut Membre 131
     
    ANNULATION DE CE MESSAGE A 2h02 PAR MOI-MÊME: REPONSE INCOMPLETE
    0
  4. Char Snipeur Messages postés 10112 Date d'inscription   Statut Contributeur Dernière intervention   1 331
     
    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
  5. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  6. cchristian Messages postés 928 Statut Membre 131
     
    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
  7. Char Snipeur Messages postés 10112 Date d'inscription   Statut Contributeur Dernière intervention   1 331
     
    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
  8. cchristian Messages postés 928 Statut Membre 131
     
    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
  9. Char Snipeur Messages postés 10112 Date d'inscription   Statut Contributeur Dernière intervention   1 331
     
    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
  10. cchristian Messages postés 928 Statut Membre 131
     
    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
  11. Char Snipeur Messages postés 10112 Date d'inscription   Statut Contributeur Dernière intervention   1 331
     
    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
  12. cchristian Messages postés 928 Statut Membre 131
     
    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