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!
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
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 = 1På 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 DODenna 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ältetKommentaren 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.
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.