Szukaj…


Domniemane typy zmiennych

Kiedy Fortran został pierwotnie opracowany, pamięć była na wagę złota. Zmienne i nazwy procedur mogą mieć maksymalnie 6 znaków, a zmienne często są niejawnie wpisywane . Oznacza to, że pierwsza litera nazwy zmiennej określa jej typ.

  • zmienne rozpoczynające się od i, j, ..., n są integer
  • wszystko inne (a, b, ..., h oraz o, p, ..., z) są real

Programy takie jak następujące są dopuszczalne 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

Możesz nawet zdefiniować swoje własne reguły niejawne za pomocą instrukcji implicit :

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

lub

! 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) 

Wpisywanie niejawne nie jest już uważane za najlepszą praktykę. Bardzo łatwo jest popełnić błąd przy użyciu pisania niejawnego, ponieważ literówki mogą pozostać niezauważone, np

program oops
  real :: somelongandcomplicatedname

  ...

  call expensive_subroutine(somelongandcomplEcatedname)
end program oops

Ten program z radością uruchomi się i zrobi coś złego.


Aby wyłączyć niejawne pisanie, można użyć implicit none instrukcji implicit none .

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

Gdybyśmy używali implicit none w programie oops powyżej, kompilator będzie zauważyli natychmiast, a produkowane błąd.

Instrukcja arytmetyczna if

Arytmetyczna instrukcja if pozwala na użycie trzech gałęzi w zależności od wyniku wyrażenia arytmetycznego

if (arith_expr) label1, label2, label3

To, if instrukcja przenosi przepływ sterowania do jednej z etykiet w kodzie. Jeśli wynik arith_expr jest ujemny, label1 to label1 , jeśli wynikiem jest zero, label2 jest label2 , a jeśli wynik jest dodatni, stosowana jest ostatnia label3 . Arytmetyka, if wymaga wszystkich trzech etykiet, ale pozwala na ponowne użycie etykiet, dlatego to stwierdzenie można uprościć do dwóch gałęzi, if .

Przykłady:

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

if (X) 100, 110, 120

Teraz ta funkcja jest przestarzała, a taką samą funkcjonalność oferuje instrukcja if i konstrukcja if-else . Na przykład fragment

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

można zapisać jako konstrukcję if-else

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

Instrukcja if zastępująca

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

może

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

Nieblokowane konstrukcje DO

Non-block do wygląda jak konstruować

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

Oznacza to, że oznaczone etykietą wypowiedzenie nie jest instrukcją continue . Istnieją różne ograniczenia dotyczące oświadczenia, które mogą być użyte jako oświadczenie o zakończeniu, a całość jest ogólnie bardzo myląca.

Taka konstrukcja nieblokowa może zostać przepisana w formie bloku jako

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

lub lepiej, używając oświadczenia o end do umowy,

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

Alternatywny zwrot

Alternatywny zwrot to narzędzie do kontrolowania przepływu wykonania po powrocie z podprogramu. Jest często używany jako forma obsługi błędów:

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

Alternatywny zwrot jest oznaczony argumentami * na podrzędnej liście argumentów podprogramu.

W powyższym zestawieniu call *100 i *200 odnoszą się do wyciągów oznaczonych odpowiednio 100 i 200 .

W samym podprogramie instrukcje return odpowiadające alternatywnemu zwrotowi mają liczbę. Liczba ta nie jest wartością zwracaną, ale oznacza dostarczoną etykietę, której wykonanie jest przekazywane po powrocie. W takim przypadku return 1 przekazuje wykonanie do instrukcji oznaczonej jako 100 a return 2 przekazuje wykonanie do instrukcji oznaczonej jako 200 . Nieadekwatna instrukcja return lub zakończenie wykonywania podprogramu bez instrukcji return przekazuje wykonanie bezpośrednio po instrukcji call.

Alternatywna składnia zwrotna bardzo różni się od innych form asocjacji argumentów, a funkcja wprowadza kontrolę przepływu w przeciwieństwie do współczesnych gustów. Bardziej przyjemną kontrolą przepływu można zarządzać przez zwrócenie liczb całkowitych „statusu” kodu.

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

Naprawiono formularz źródłowy

Fortran pierwotnie został zaprojektowany dla formatu o stałym formacie opartym na 80-kolumnowej karcie perforowanej:

wprowadź opis zdjęcia tutaj

Tak: To jest linia własnego kodu autora

Zostały one utworzone na maszynie do dziurkowania kart, podobnie jak to:

wprowadź opis zdjęcia tutaj

Obrazy są oryginalną fotografią autora

Format, jak pokazano na zilustrowanej przykładowej karcie, miał pierwsze pięć kolumn zarezerwowanych dla etykiet wyciągów. Pierwsza kolumna posłużyła do oznaczenia komentarzy literą C. Szósta kolumna została użyta do oznaczenia kontynuacji instrukcji (poprzez wstawienie dowolnego znaku innego niż zero „0”). Ostatnie 8 kolumn wykorzystano do identyfikacji i sekwencjonowania kart, co było bardzo cenne, jeśli upuściłeś swoją talię kart na podłogę! Kodowanie znaków dla kart perforowanych miało ograniczony zestaw znaków i było pisane tylko dużymi literami. W rezultacie programy Fortran wyglądały tak:

       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

Znak spacji był również wszędzie ignorowany, z wyjątkiem wewnątrz stałej postaci Hollerith (jak pokazano powyżej). Oznaczało to, że spacje mogą występować w zarezerwowanych słowach i stałych lub całkowicie pominięte. Miało to efekt uboczny niektórych dość mylących stwierdzeń, takich jak:

       DO 1 I = 1.0

jest przypisaniem do zmiennej DO1I podczas gdy:

       DO1I = 1,0 

jest w rzeczywistości pętlą DO zmiennej I


Modern Fortran nie wymaga teraz tej stałej formy wprowadzania danych i zezwala na dowolną formę przy użyciu dowolnych kolumn. Komentarze są teraz oznaczone symbolem ! które można również dołączyć do wiersza instrukcji. Spacje nie są teraz nigdzie dozwolone i muszą być używane jako separatory, podobnie jak w większości innych języków. Powyższy program można napisać we współczesnym Fortranie jako:

! 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"

Chociaż kontynuacja w starym stylu nie jest już używana, powyższy przykład pokazuje, że nadal będą występować bardzo długie instrukcje. Modern Fortran używa symbolu & na końcu i na początku kontynuacji. Na przykład moglibyśmy napisać powyższe w bardziej czytelnej formie:

! 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"

Wspólne bloki

We wczesnych formach Fortrana jedynym mechanizmem tworzenia globalnego magazynu zmiennych widocznego z podprogramów i funkcji jest użycie mechanizmu COMMON bloku. Dzięki temu sekwencje zmiennych mogły być wspólne i wspólne.

Oprócz nazwanych wspólnych bloków może również istnieć pusty (nienazwany) wspólny blok.

Pusty wspólny blok może być zadeklarowany jak

common i, j

podczas gdy nazwane variables blokowe można zadeklarować jak

common /variables/ i, j

Jako kompletny przykład możemy sobie wyobrazić magazyn sterty, który jest używany przez procedury, które mogą dodawać i usuwać wartości:

       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

Za pomocą wspólnych instrukcji można niejawnie zadeklarować typ zmiennej i określić atrybut dimension . Samo to zachowanie jest często wystarczającym źródłem zamieszania. Co więcej, implikowane powiązanie pamięci i wymagania dotyczące powtarzających się definicji w jednostkach programu sprawiają, że stosowanie typowych bloków jest podatne na błędy.

Wreszcie, wspólne bloki są bardzo ograniczone w obiektach, które zawierają. Na przykład tablica we wspólnym bloku musi mieć jawny rozmiar; przydzielane obiekty mogą nie wystąpić; typy pochodne nie mogą mieć domyślnej inicjalizacji.

We współczesnym Fortranie to dzielenie się zmiennymi można obsłużyć za pomocą modułów . Powyższy przykład można zapisać jako:

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

Nazwane i puste wspólne bloki mają nieco inne zachowania. Nutowy:

  • obiekty w nazwanych wspólnych blokach można wstępnie zdefiniować; przedmioty w pustym wspólnym obiekcie nie będą
  • obiekty w pustych wspólnych blokach zachowują się tak, jakby wspólny blok miał atrybut save ; obiekty w nazwanych wspólnych blokach bez atrybutu save mogą stać się niezdefiniowane, gdy blok nie wchodzi w zakres aktywnej jednostki programowej

Ten ostatni punkt można przeciwstawić zachowaniu zmiennych modułowych we współczesnym kodzie. Wszystkie zmienne modułu w Fortran 2008 są domyślnie zapisywane i nie stają się niezdefiniowane, gdy moduł wykracza poza zakres. Przed Fortran 2008 zmienne modułowe, takie jak zmienne w nazwanych wspólnych blokach, również stałyby się niezdefiniowane, gdy moduł wykraczał poza zakres.

Przypisano GOTO

Przypisany GOTO używa zmiennej całkowitej, do której przypisana jest etykieta instrukcji za pomocą instrukcji ASSIGN.

100 CONTINUE

...

ASSIGN 100 TO ILABEL

...


GOTO ILABEL

Przypisane GOTO jest przestarzałe w Fortran 90 i usunięte w Fortran 95 i nowszych. W nowoczesnym kodzie można tego uniknąć, stosując procedury, procedury wewnętrzne, wskaźniki procedur i inne funkcje.

Obliczone GOTO

Obliczone GOTO pozwala na rozgałęzienie programu zgodnie z wartością wyrażenia całkowitego.

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

Jeśli scalar-integer-expression jest równe 1, program kontynuuje pracę na etykiecie instrukcji label_1 , jeśli jest równy 2, przechodzi do label_2 i tak dalej. Jeśli jest mniejsza niż 1 lub większa niż n program kontynuuje w następnym wierszu.

Przykład:

ivar = 2

...

GOTO (10, 20, 30, 40) ivar

przejdzie do etykiety oświadczenia 20.

Ta forma goto jest przestarzała w Fortran 95 i późniejszych wersjach, zastępując ją konstrukcją select case .

Przypisane specyfikatory formatu

Przed Fortranem 95 możliwe było stosowanie przypisanych formatów dla danych wejściowych lub wyjściowych. Rozważać

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

Instrukcja assign przypisuje etykietę instrukcji do zmiennej całkowitej. Ta zmienna całkowita jest później używana jako specyfikator formatu w instrukcji print .

Takie przypisanie specyfikatora formatu zostało usunięte w Fortran 95. Zamiast tego, bardziej nowoczesny kod może używać innej formy kontroli przepływu wykonywania

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

lub zmienna znakowa może być użyta jako specyfikator formatu

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

Funkcje instrukcji

Rozważ program

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

print *, f(1)
end

Tutaj f jest funkcją instrukcji. Ma typ wyniku liczb całkowitych, biorąc jeden argument fikcyjny liczby całkowitej. 1

Taka funkcja instrukcji istnieje w zakresie, w którym jest zdefiniowana. W szczególności ma dostęp do zmiennych i nazwanych stałych dostępnych w tym zakresie.

Jednak funkcje instrukcji podlegają wielu ograniczeniom i mogą być mylące (patrząc na przypadkowy wygląd jak instrukcja przypisania elementu tablicy). Ważne ograniczenia to:

  • wynik funkcji i fikcyjne argumenty muszą być skalarne
  • fikcyjne argumenty mają ten sam zakres co funkcja
  • funkcje instrukcji nie mają lokalnych zmiennych
  • funkcje instrukcji nie mogą być przekazywane jako rzeczywiste argumenty

Główne zalety funkcji instrukcji są powtarzane przez funkcje wewnętrzne

implicit none

print *, f(1)

contains

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

end

Funkcje wewnętrzne nie podlegają wymienionym wyżej ograniczeniom, chociaż być może warto zauważyć, że wewnętrzny podprogram może nie zawierać dalszego wewnętrznego podprogramu (ale może zawierać funkcję instrukcji).

Funkcje wewnętrzne mają swój zakres, ale także dostępne powiązanie hosta.


1 W prawdziwych starych przykładach kodu nie byłoby niczym niezwykłym, że fikcyjne argumenty funkcji instrukcji są domyślnie wpisywane, nawet jeśli wynik ma typ jawny.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow