Sök…


Implicita variabeltyper

När Fortran ursprungligen utvecklades var minnet högt. Variabler och procedurnamn kan ha högst 6 tecken, och variabler skrivs ofta implicit . Detta innebär att den första bokstaven i variabelns namn bestämmer dess typ.

  • variabler som börjar med i, j, ..., n är integer
  • allt annat (a, b, ..., h, och o, p, ..., z) är real

Program som följande är acceptabla Fortran:

program badbadnotgood
  j = 4
  key = 5 ! only the first letter determines the type
  x = 3.142
  print*, "j = ", j, "key = ", key, "x = ", x
end program badbadnotgood

Du kan till och med definiera dina egna implicita regler med det implicit uttalandet:

! all variables are real by default 
implicit real (a-z)

eller

! variables starting with x, y, z are complex
! variables starting with c, s are character with length of 4 bytes
! and all other letters have their default implicit type
implicit complex (x,y,z), character*4 (c,s) 

Implicit typning anses inte längre vara bästa praxis. Det är mycket lätt att göra ett misstag med implicit typning, eftersom skrivfel kan gå obemärkt, t.ex.

program oops
  real :: somelongandcomplicatedname

  ...

  call expensive_subroutine(somelongandcomplEcatedname)
end program oops

Det här programmet körs gärna och gör fel sak.


För att stänga av implicit typ kan det implicit none uttalande användas.

program much_better
  implicit none
  integer :: j = 4
  real :: x = 3.142
  print*, "j = ", j, "x = ", x
end program much_better

Om vi hade använt implicit none i programmet oops ovan, skulle kompilatorn omedelbart ha märkt det och skapat ett fel.

Aritmetisk om uttalande

Aritmetisk if uttalande tillåter en att använda tre grenar beroende på resultatet av ett aritmetiskt uttryck

if (arith_expr) label1, label2, label3

Detta if uttalandet överför kontrollflödet till en av etiketterna i en kod. Om resultatet av arith_expr är negativt är label1 involverat, om resultatet är noll label2 används, och om resultatet är positivt label3 sista label3 . Aritmetik if krävs alla tre etiketter men det tillåter återanvändning av etiketter, därför kan detta uttalande förenklas till en tvågren if .

Exempel:

if (N * N - N / 2) 130, 140, 130

if (X) 100, 110, 120

Nu är den här funktionen föråldrad med samma funktionalitet som erbjuds av if uttalandet och if-else konstruktionen. Till exempel fragmentet

    if (X) 100, 110, 120
100 print*, "Negative"
    goto 200
110 print*, "Zero"
    goto 200
120 print*, "Positive"
200 continue

kan skrivas som if-else konstruktionen

if (X<0) then
  print*, "Negative"
else if (X==0) then
  print*, "Zero"
else
  print*, "Positive"
end if

En if uttalande ersättning för

    if (X) 100, 100, 200
100 print *, "Negative or zero"
200 continue

kanske

if (X<=0) print*, "Negative or zero"

Icke-blockera DO-konstruktioner

Den icke-blockera do konstruktionen ser ut

    integer i
    do 100, i=1, 5
100 print *, i

Det vill säga där det märkta uppsägningsuttalandet inte är ett continue . Det finns olika begränsningar för uttalandet som kan användas som uppsägningsuttalande och hela saken är i allmänhet väldigt förvirrande.

En sådan icke-blockkonstruktion kan skrivas om i blockform som

    integer i
    do 100 i=1,5
      print *, i
100 continue

eller bättre, med hjälp av en end do avslutnings uttalande,

integer i
do i=1,5
  print *, i
end do

Alternativ avkastning

Alternativ återgång är en anordning för att kontrollera körningsflödet vid retur från en subrutin. Det används ofta som en form av felhantering:

real x

call sub(x, 1, *100, *200)
print*, "Success:", x
stop

100 print*, "Negative input value"
stop

200 print*, "Input value too large"
stop

end

subroutine sub(x, i, *, *)
  real, intent(out) :: x
  integer, intent(in) :: i
  if (i<0) return 1
  if (i>10) return 2
  x = i
end subroutine

Den alternativa returen markeras med argumenten * i listan med subroutine dummy.

I call ovan *100 och *200 hänvisas till uttalanden märkta 100 respektive 200 .

I subrutinen själv return uttalanden motsvarande alternativ avkastning har ett antal. Detta nummer är inte ett returvärde, men anger den medföljande etiketten som exekveringen skickas vid returen. I detta fall överlämnar return 1 exekvering till uttalandet som är märkt 100 och return 2 överför exekvering till uttalandet märkt 200 . En avskalade return uttalande eller slutförande av exekverings subrutin utan return uttalande passess utförande omedelbart efter samtalet uttalande.

Alternativ syntax är mycket annorlunda än andra former av argumentförening och anläggningen introducerar flödeskontroll i motsats till modern smak. Mer behaglig flödeskontroll kan hanteras med returnering av en heltalskod "status".

real x
integer status

call sub(x, 1, status)
select case (status)
case (0)
  print*, "Success:", x
case (1)
  print*, "Negative input value"
case (2)
  print*, "Input value too large"
end select

end

subroutine sub(x, i, status)
  real, intent(out) :: x
  integer, intent(in) :: i
  integer, intent(out) :: status

  status = 0

  if (i<0) then
    status = 1
  else if (i>10)
    status = 2
  else
    x = i
  end if

end subroutine

Fast källformulär

Fortran designades ursprungligen för ett fast formatformat baserat på ett stansat kort med 80 kolumner:

ange bildbeskrivning här

Ja: Det här är en rad med författarens egen kod

Dessa skapades på en kortstansmaskin, ungefär så här:

ange bildbeskrivning här

Bilder är originalfotografering av författaren

Formatet, som visas på det illustrerade provkortet, hade de första fem kolumnerna reserverade för uttalandeetiketter. Den första kolumnen användes för att beteckna kommentarer med en bokstav C. Den sjätte kolumnen användes för att beteckna en fortsättning av uttalandet (genom att infoga något annat tecken än noll '0'). De sista 8 kolumnerna användes för kortidentifiering och sekvensering, vilket var ganska värdefullt om du tappade ditt kortlek på golvet! Teckenkodningen för stansade kort hade bara en begränsad uppsättning tecken och var endast versaler. Som ett resultat såg Fortran-program så ut:

       DIMENSION A(10)                                                    00000001
C THIS IS A COMMENT STATEMENT TO EXPLAIN THIS EXAMPLE PROGRAM             00000002
       WRITE (6,100)                                                      00000003
 100   FORMAT(169HTHIS IS A RATHER LONG STRING BEING OUTPUT WHICH GOES OVE00000004
      1R MORE THAN ONE LINE, AND USES THE STATEMENT CONTINUATION MARKER IN00000005
      2COLUMN 6, AND ALSO USES HOLLERITH STRING FORMAT)                   00000006
       STOP                                                               00000007
       END                                                                00000008

Rymdkaraktären ignorerades också överallt, utom i en Hollerith- karaktärskonstant (som visas ovan). Detta innebar att utrymmen kunde uppstå i reserverade ord och konstanter, eller helt missade. Detta hade bieffekten av några ganska vilseledande uttalanden som:

       DO 1 I = 1.0

är en tilldelning till variabeln DO1I medan:

       DO1I = 1,0 

är faktiskt en DO slinga på variabeln I


Modern Fortran kräver inte denna fasta inmatningsform och tillåter fri form med hjälp av några kolumner. Kommentarer indikeras nu av a ! som också kan bifogas till en uttalande rad. Utrymmen är nu inte tillåtna någonstans och måste användas som separatorer, precis som på de flesta andra språk. Ovanstående program kan skrivas i modernt Fortran som:

! This is a comment statement to explain this example program
Print *,"THIS IS A RATHER LONG STRING BEING OUTPUT WHICH no longer GOES OVER MORE THAN ONE LINE, AND does not need to USE THE STATEMENT CONTINUATION MARKER IN COLUMN 6, or the HOLLERITH STRING FORMAT"

Även om den gamla stilen fortsätter inte längre används, illustrerar exemplet ovan att mycket långa uttalanden fortfarande kommer att inträffa. Modern Fortran använder en & symbol i slutet och början av fortsättningen. Vi kan till exempel skriva ovanstående i en mer läsbar form:

! This is a comment statement to explain this example program
Print *,"THIS IS A RATHER LONG STRING BEING OUTPUT WHICH still &
         &GOES OVER MORE THAN ONE LINE, AND does need to USE THE STATEMENT &
         &CONTINUATION notation"

Vanliga block

I de tidiga formerna av Fortran är den enda mekanismen för att skapa global variabel butik synlig från subroutiner och funktioner att använda den COMMON . Detta tillät sekvenser av variabler att namnges och delas gemensamt.

Förutom namngivna vanliga block kan det också finnas ett tomt (ej namngivet) gemensamt block.

Ett tomt gemensamt block kan förklaras som

common i, j

medan de nämnda variables kan deklareras som

common /variables/ i, j

Som ett komplett exempel kan vi föreställa oss en heap-butik som används av rutiner som kan lägga till och ta bort värden:

       PROGRAM STACKING
       COMMON /HEAP/ ICOUNT, ISTACK(1023)
       ICOUNT = 0
       READ *, IVAL
       CALL PUSH(IVAL)
       CALL POP(IVAL)
       END

       SUBROUTINE PUSH(IVAL)
       COMMON /HEAP/ ICOUNT, ISTACK(1023)
       ICOUNT = ICOUNT + 1
       ISTACK(ICOUNT) = IVAL
       RETURN
       END

       SUBROUTINE POP(IVAL)
       COMMON /HEAP/ ICOUNT, ISTACK(1023)
       IVAL = ISTACK(ICOUNT)
       ICOUNT = ICOUNT - 1
       RETURN
       END

Vanliga uttalanden kan användas för att implicit deklarera typen av en variabel och för att specificera dimension attribut. Detta beteende ensam är ofta en tillräcklig källa till förvirring. Vidare gör den underförstådda lagringsassociationen och kraven på upprepade definitioner över programenheter användningen av vanliga block som är benägna att fel.

Slutligen är vanliga block mycket begränsade i de objekt de innehåller. Till exempel måste en matris i ett gemensamt block vara av uttrycklig storlek; allokerbara objekt kanske inte inträffar; härledda typer får inte ha standardinitialisering.

I moderna Fortran kan denna delning av variabler hanteras med hjälp av moduler . Exemplet ovan kan skrivas som:

module heap
  implicit none
  ! In Fortran 2008 all module variables are implicitly saved
  integer, save :: count = 0
  integer, save :: stack(1023)
end module heap

program stacking
  implicit none
  integer val
  read *, val
  call push(val)
  call pop(val)

contains
  subroutine push(val)
    use heap, only : count, stack
    integer val
    count = count + 1
    stack(count) = val
  end subroutine push

  subroutine pop(val)
    use heap, only : count, stack
    integer val
    val = stack(count)
    count = count - 1
  end subroutine pop
end program stacking

Namngivna och tomma vanliga block har något olika beteenden. Av anmärkning:

  • objekt i namngivna vanliga block kan definieras initialt; föremål i tomt gemensamt ska inte vara
  • objekt i tomma gemensamma block fungerar som om det gemensamma blocket har attributet save ; objekt i namngivna vanliga block utan attributet save kan bli odefinierade när blocket inte ligger inom ramen för en aktiv programenhet

Den senare punkten kan kontrasteras med modulvariablernas beteende i modern kod. Alla modulvariabler i Fortran 2008 sparas implicit och blir inte odefinierade när modulen går utanför räckvidden. Innan modulvariablerna för Fortran 2008, som variabler i nämnda gemensamma block, skulle också bli odefinierade när modulen gick utanför räckvidden.

Tilldelad GOTO

Tilldelad GOTO använder heltalvariabel till vilken en uttalande etikett tilldelas med ASSIGN-uttalandet.

100 CONTINUE

...

ASSIGN 100 TO ILABEL

...


GOTO ILABEL

Tilldelad GOTO är föråldrad i Fortran 90 och raderas i Fortran 95 och senare. Det kan undvikas i modern kod genom att använda procedurer, interna procedurer, procedurpekare och andra funktioner.

Beräknad GOTO

Beräknad GOTO tillåter förgrening av programmet enligt värdet på ett heltaluttryck.

GOTO (label_1, label_2,... label_n) scalar-integer-expression

Om scalar-integer-expression är lika med 1 fortsätter programmet vid uttalande label_1 , om det är lika med 2 går det till label_2 och så vidare. Om det är mindre än 1 eller större än n fortsätter programmet på nästa rad.

Exempel:

ivar = 2

...

GOTO (10, 20, 30, 40) ivar

kommer att gå till uttalande etikett 20.

Denna form av goto är föråldrad i Fortran 95 och senare och ersätts av select case .

Tilldelade formatspecifikationer

Innan Fortran 95 var det möjligt att använda tilldelade format för input eller output. Överväga

integer i, fmt
read *, i

assign 100 to fmt
if (i<100000) assign 200 to fmt

print fmt, i

100 format ("This is a big number", I10)
200 format ("This is a small number", I6)

end

assign tilldelar en uttalande etikett till en heltalvariabel. Denna heltalvariabel används senare som formatspecifikationen i print .

Sådan formatspecifikationstilldelning raderades i Fortran 95. I stället kan mer modern kod använda någon annan form av exekveringsflödeskontroll

integer i
read *, i

if (i<100000) then
  print 100, i
else
  print 200, i
end if

100 format ("This is a big number", I10)
200 format ("This is a small number", I6)

end

eller en teckenvariabel kan användas som formatspecifikation

character(29), target :: big_fmt='("This is a big number", I10)'
character(30), target :: small_fmt='("This is a small number", I6)'
character(:), pointer :: fmt

integer i
read *, i

fmt=>big_fmt
if (i<100000) fmt=>small_fmt

print fmt, i

end

Uttalande funktioner

Tänk på programmet

implicit none
integer f, i
f(i)=i

print *, f(1)
end

Här är f en uttalande funktion. Den har heltal resultattyp, tar ett heltal dummy argument. 1

En sådan uttalande funktion finns inom ramen för den definieras. I synnerhet har den tillgång till variabler och namngivna konstanter som är tillgängliga inom det omfånget.

Uttagsfunktioner är emellertid föremål för många begränsningar och är potentiellt förvirrande (titta på en tillfällig blick som en uppsättning av arrayelement). Viktiga begränsningar är:

  • funktionsresultatet och dummy-argumenten måste vara skalära
  • dummy-argumenten är i samma omfattning som funktionen
  • uttalande funktioner har inga lokala variabler
  • uttalande funktioner kan inte skickas som faktiska argument

De viktigaste fördelarna med uttalande funktioner upprepas av interna funktioner

implicit none

print *, f(1)

contains

  integer function f(i)
    integer i
    f = i
  end function

end

Interna funktioner omfattas inte av de ovan nämnda begränsningarna, även om det kanske är värt att notera att ett internt underprogram inte kan innehålla ytterligare internt underprogram (men det kan innehålla en uttalande funktion).

Interna funktioner har sin egen räckvidd men har också tillgänglig värdförening.


1 I verkliga gamla kodexempel skulle det inte vara ovanligt att se dummy-argumenten för en uttalande funktion implicit skrivas, även om resultatet har en uttrycklig typ.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow