COMMON A, B, C, D ! I huvudprogrammet COMMON A, B, X, C ! I subrutinenOm 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, VAR2dvs 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!
Här följer det reviderade programmet
som utnyttjar en modul
i stället för COMMON och BLOCK DATA.
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
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.
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.
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.
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
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.
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.
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.
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.
Senast modifierad: 27 juli 1999
boein@nsc.liu.se