13. Diverse begrepp från Fortran 77

13.0 Inledning

Fortran 77 innehåller en del begrepp som inte så naturligt passar in i beskrivningen av Fortran 90. De ersättes i huvudsak av nyare begrepp i Fortran 90, och bör därför undvikas i så stor omfattning som möjligt.

13.1 COMMON

Med hjälp av COMMON kan man på ett smidigt, effektivt och riskfyllt sätt överföra data mellan olika programenheter (huvudprogram, subrutin, funktion). Härvid utnyttjas samma lagringsutrymme i minnet för de data som hör till de olika programenheterna.
        COMMON A, B, C, D   ! I huvudprogrammet
        COMMON A, B, X, C   ! I subrutinen
Om ovanstående båda satser finns med den första i huvudprogrammet och den andra i subrutinen kommer de båda variablerna A och B att vara gemensamma, medan C i huvudprogrammet heter X i subrutinen och D i huvudprogrammet heter C i subrutinen (vilket är förvirrande). Om de motsvarande variablerna har samma datatyp (och slag) kommer de även att ha samma värde.

Formella parametrar (argument) får ej ingå i COMMON!

Det finns två varianter av COMMON, nämligen dels ett som ser ut som ovan (utan namn, kallat blank COMMON), dels namnade COMMON. Det senare är av formen

        COMMON / BLOCK1 / VAR1, VAR2
dvs namnet på COMMON-blocket ges inom snedstreck. Storheter i namnat COMMON får ej ingå i SAVE, men väl ett helt namnat COMMON, se vidare avsnittet 13.3. Även då skall namnet på COMMON-blocket ges inom snedstreck.

Varning: Om variablerna i ett COMMON-block ej överensstämmer, mellan de olika förekomsterna i de olika programenheterna, till ordning, typ och slag, samt till storlek (antal element vid fält) blir det fel. Dessutom gäller att textsträngsvariabler (CHARACTER) ej får finnas i ett COMMON-block som även innehåller variabler av andra slag.

Blankt COMMON kan även skapas som ett namnat COMMON, men med ingenting (blankt) mellan snedstrecken. Därav namnet!

Om variabeln C i huvudprogrammet ovan är av typ DOUBLE PRECISION, och variablerna X och C i subrutinen är av typ REAL, så kommer C i huvudprogrammet att i normalfallet omfatta samma lagringsutrymme som X och C i subrutinen, varför D i huvudprogrammet och C i subrutinen inte kommer att ha något gemensamt. Normalt upptar ju en dubbelprecisionsvariabel dubbelt så stort lagrringsutrymme som en enkelprecisionsvariabel.

Initiering av variabler i ett COMMON-block sker geom att utnyttja BLOCK DATA.

I Fortran 90 kan man utnyttja moduler för att på ett säkrare sätt överföra bland annat data mellan olika programenheter. Se även sektion 14.4.3, där ett exempel som något liknar COMMON ges.

Jag rekommenderar naturligtvis att göra om COMMON till moduler, och ger därför ett enkelt exempel nedan. Ett allvarligt problem uppstår dock i de fall som man utnyttjat någon av de ovan nämnda "konstigheterna", speciellt då möjligheten att en variabel har olika namn i olika programenheter. Detta kan ej realiseras med moduler, utan antingen måste man byta till ett konsekvent namn eller behålla COMMON.

I exemplet common.f90 nedan finns ett program som innehåller ett huvudprogram, en subrutin och en funktion samt utnyttjar ett blankt COMMON och ett namnat COMMON /BLOCK1/, vars variabler getts värden i BLOCK DATA BD1. Detta exempel har reviderats till modul.f90 där COMMON-variablerna flyttats till en modul MD1. På flera system krävs att modulen ligger först i filen, eller är i den första filen som kompileras/länkas!

PROGRAM TEST_AV_COMMON
        IMPLICIT NONE
        REAL :: A, B, C, D, E, F
        REAL, EXTERNAL :: FUN
        COMMON A, B
        COMMON /BLOCK1/ C, D
        WRITE(*,*) ' Början av programmet TEST_AV_COMMON'
        CALL SUB1(A, B)
        E = A + B
        F = FUN(A+C) 
        WRITE(*,*) ' E = ', E,  ' F = ', F
        WRITE(*,*) ' Slutet av programmet TEST_AV_COMMON'
END PROGRAM TEST_AV_COMMON

BLOCK DATA BD1
        IMPLICIT NONE
        REAL :: C, D
        COMMON /BLOCK1/ C, D
        DATA C, D / 1.0, 19.0 /
END BLOCK DATA BD1

SUBROUTINE SUB1(X, Y)
        IMPLICIT NONE
        REAL :: A, B, C, D, X, Y
        COMMON A, B
        COMMON /BLOCK1/ C, D
        X = C
        Y = D
        WRITE(*,'(A)', ADVANCE='NO') '  Ge A = '
        READ(*,*) A
        WRITE(*,'(A)', ADVANCE='NO') '  Ge B = '
        READ(*,*) B
END SUBROUTINE SUB1

REAL FUNCTION FUN(X)
        IMPLICIT NONE
        REAL :: A, B, C, D, X
        COMMON A, B
        COMMON /BLOCK1/ C, D
        FUN = X + D
END FUNCTION FUN

Här följer det reviderade programmet som utnyttjar en modul i stället för COMMON och BLOCK DATA.

MODULE MD1
        IMPLICIT NONE
        REAL :: A, B, C, D
        DATA C, D / 1.0, 19.0 /
END MODULE MD1

PROGRAM TEST_AV_MODUL
        USE MD1
        IMPLICIT NONE
        REAL :: E, F
        REAL, EXTERNAL :: FUN
        WRITE(*,*) ' Början av programmet TEST_AV_MODUL'
        CALL SUB1(A, B)
        E = A + B
        F = FUN(A+C) 
        WRITE(*,*) ' E = ', E,  ' F = ', F
        WRITE(*,*) ' Slutet av programmet TEST_AV_MODUL'
END PROGRAM TEST_AV_MODUL

SUBROUTINE SUB1(X, Y)
        USE MD1
        IMPLICIT NONE
        REAL :: X, Y
        X = C
        Y = D
        WRITE(*,'(A)', ADVANCE='NO') '  Ge A = '
        READ(*,*) A
        WRITE(*,'(A)', ADVANCE='NO') '  Ge B = '
        READ(*,*) B
END SUBROUTINE SUB1

REAL FUNCTION FUN(X)        
        USE MD1
        IMPLICIT NONE
        REAL :: X
        FUN = X + D
END FUNCTION FUN

13.2 EQUIVALENCE

Med COMMON delar variabler mellan olika programenheter samma lagringsutrymme, men med EQUIVALENCE delar i stället olika variabler i samma programenhet på utrymme.
        REAL :: A, B, C, D, E
        REAL, DIMENSION(10) :: G
        EQUIVALENCE (A, B), (C, D, E)
        EQUIVALENCE (C, G(7))
Med ovanstående delar flyttalsvariablerna A och B på samma lagringsutrymme (och värde), medan flyttalsvariablerna C, D och E samt flyttalselementet G(7) delar på ett annat utrymme.
        COMPLEX CC
        REAL A
        EQUIVALENCE(CC, A)
Med ovanstående blir flyttalsvariabeln A realdelen av det komplexa flyttalet CC.
        DOUBLE PRECISION D
        REAL A
        EQUIVALENCE (A,D)
Med ovanstående blir flyttalsvariabeln A enkelprecisionsvärdet av dubbelprecisions-flyttalet D på en del datorsystem, men helt fel på de flesta datorsystem.
        REAL :: A
        INTEGER :: I
        EQUIVALENCE (A,I)
        I = 1
På de flesta datorsystem innebär ovanstående att flyttalet A blir ett litet tal, oftast noll.

Förutom för att spara lagringsutrymme kan EQUIVALENCE användas för att ta bort verkan av konsekventa stavfel. Om man har ett program med flyttalsvariabeln DEFENCE kan man ibland ha stavat den på amerikanska, dvs DEFENSE. Man kan göra dessa ekvivalenta med satsen

        EQUIVALENCE (DEFENCE, DEFENSE)
En bättre metod att åtgärda ett sådant fel är att bestämma sig för vilken stavning (motsvarande) som skall gälla och använda editorn till att ändra till rätt variabelnamn.

En annan användning av EQUIVALENCE var då man ville nollställa ett helt flerdimensionellt fält. I nedanstående slinga nollställes således det tre-dimensionella fältet A med en enkel slinga.

        REAL, DIMENSION(10,10,10) :: A
        REAL, DIMENSION(1000) :: B
        EQUIVALENCE (A, B)
        DO I = 1, 1000
           B(I) = 0.0
        END DO
Denna användning är helt olämplig i Fortran 90, där man har tillgång till kraftfulla fältkommandon. Avsnittet blir i stället
        REAL, DIMENSION(10,10,10) :: A
        A = 0.0 ! Nollställning av hela fältet
Kommentaren på raden är bra för att påminna läsaren om att det inte är en enkel (skalär) variabel som skall nollställas, utan ett helt fält.

I Fortran 90 bör man helst undvika EQUIVALENCE, det kan dock ibland behöva utnyttjas när man vill kontrollera (simulera) vad som sker vid användning av fel datatyp vid exempelvis funktionsanrop.

13.3 SAVE

Detta är ett begrepp som infördes i Fortran 77 och inte fanns i tidigare standard, och knappast heller i tidigare implementationer.

Anledningen är det välkända fenomenet att vid uthopp från en funktion eller subrutin så glöms automatiskt värdena på alla lokala variabler (utom de som antingen givits begynnelsevärden med DATA-sats eller motsvarande och ej modifierats, eller de som getts som permanenta konstanter med satsen eller attributet PARAMETER). Anledningen till denna "glömska" är att man vid behov av minnesutrymme skall kunna växla ut (eng. swap) rutinen från primärminnet till skivminnet. Om inga värden behöver sparas från exekveringen behöver man då bara på nytt kopiera in rutinen till primärminnet från skivminnet, men aldrig kopiera tillbaks den från primärminnet till skivminnet. Man undviker således halva arbetet!

För att kunna spara värden har därför satsen (och attributet) SAVE införts. Om det står ensamt på en rad bland deklarationerna innebär det att alla variabler skall sparas. Alternativt ger man det som en vanlig deklaration, dvs man räknar efter kommandot SAVE upp de variabler och/eller COMMON block som skall sparas. Observera att enskilda variabler i COMMON block ej kan sparas, utan bara hela namnade COMMON block.

I ett eventuellt onamnat (blank) COMMON sparas automatiskt (obligatoriskt) alla variabler. För övriga COMMON block gäller att värdena sparas automatiskt om COMMON blocket finns längre upp i anropssekvensen av funktioner och subrutiner. Klarare uttryckt, om en subrutin anropar två subrutiner som innehåller samma namnade COMMON block bör detta COMMON block även finnas i den anropande subrutinen.

Pekare Innehåll Program-uppbyggnad


Senast modifierad: 27 juli 1999
boein@nsc.liu.se