サーチ…


暗黙の変数型

Fortranが最初に開発されたとき、メモリはプレミアムでした。変数とプロシージャー名には最大6文字を使用でき、変数には暗黙的に入力されることがよくあります。これは、変数名の最初の文字がその型を決定することを意味します。

  • i、j、...、nで始まる変数はinteger
  • 他のすべて(a、b、...、h、o、p、...、z)はreal

次のようなプログラムが許容されます。

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

implicitステートメントで独自の暗黙ルールを定義することさえできます:

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

または

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

暗黙の型指定はもはやベストプラクティスとみなされます。タイプミスが気付かれないことがあるので、暗黙の型定義を使用して間違いを作るのはとても簡単です。

program oops
  real :: somelongandcomplicatedname

  ...

  call expensive_subroutine(somelongandcomplEcatedname)
end program oops

このプログラムは楽しく実行され、間違ったことをします。


暗黙の型指定を無効にするには、 implicit noneステートメントを使用できます。

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

私たちが使用していなかった場合はimplicit noneプログラムでoops以上、コンパイラはすぐに気づいた、とエラーが発生しているだろう。

算術ifステートメント

算術式if文は、算術式の結果に応じて3つの分岐を使用できる

if (arith_expr) label1, label2, label3

このif文は、制御フローをコード内のラベルの1つに転送します。 arith_exprの結果が負の場合はlabel1が関与し、結果がゼロの場合はlabel2が使用され、結果が正の場合は最後のlabel3が適用されます。算術演算if 、すべての3つのラベルが必要ですが、それゆえ、この文は2つの分岐に簡略化することができ、ラベルの再利用を許可するif

例:

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

if (X) 100, 110, 120

現在、この機能は廃止されており、 if文とif-else構文によって同じ機能が提供されていif-else 。例えば、フラグメント

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

if-else構文として書くことができます

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

ifステートメントの置換

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

多分

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

非ブロックDO構造

非ブロックdo構造は次のようになります

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

つまり、ラベル付き終了文がcontinue文ではない場合です。終了ステートメントとして使用できるステートメントにはさまざまな制限があり、全体的には非常に混乱します。

このような非ブロック構造は、ブロック形式で次のように書き直すことができます。

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

end doステートメントを使用して、

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

代替リターン

代替リターンは、サブルーチンからの復帰時に実行フローを制御する機能です。これはしばしばエラー処理の一種として使われます:

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

代替リターンは、サブルーチン仮引数リストの引数*によってマークされます。

*100*200上のcall文では、それぞれ100200というラベルのステートメントを参照してください。

サブルーチン自体では、代替リターンに対応するreturn文には番号があります。この数値は戻り値ではなく、実行時に返される提供ラベルを示します。この場合、 return 1は実行を100というラベルのステートメントに渡し、 return 2は実行を200というラベルのステートメントに渡します。飾り気のないreturnのない声明、またはサブルーチンの実行の完了return声明、passess実行にすぐに呼び出し文の後に。

代替の戻り構文は、他の形式の引数関連とは非常に異なり、この機能は現代の趣旨に反してフロー制御を導入します。整数の「ステータス」コードが返され、より快適なフロー制御が管理できます。

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

固定ソースフォーム

Fortranはもともと、80列のパンチカードをベースにした固定書式用に設計されていました。

ここに画像の説明を入力

はい:これは著者自身のコードの行です

これらは、次のようにカードパンチマシンで作成されました。

ここに画像の説明を入力

画像は著者によるオリジナル写真です

図示のサンプルカードに示されているように、書式ラベルの最初の5列が予約されています。最初の列は、文字Cでコメントを示すために使用された。 6番目の列は、文の継続を示すために使用されます(0以外の文字を挿入することによって)。最後の8列は、カードの識別と順序付けに使用されました。これは、カードのデッキを床に落とした場合にはかなり価値がありました!穿孔されたカードの文字コーディングには、限られた文字セットしかなく、大文字のみでした。その結果、Fortranプログラムは次のようになりました。

       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

スペース文字は、 ホレリス文字定数の中を除いて(上記のように)どこでも無視されました。これは、スペースが予約語や定数の内部で発生する可能性があること、または完全に欠落していることを意味していました。これには、以下のような誤解を招くような文章の副作用がありました。

       DO 1 I = 1.0

変数DO1Iへの代入でDO1I

       DO1I = 1,0 

実際には変数I上のDOループです。


現代のFortranでは、この固定形式の入力は不要であり、任意の列を使用した自由形式が可能です。コメントは!示されます!ステートメント行に追加することもできます。スペースは現在どこでも許可されておらず、他のほとんどの言語と同様にセパレータとして使用する必要があります。上記のプログラムは、現代のFortranで次のように記述することができます:

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

古いスタイルの継続はもう使用されませんが、上記の例は、非常に長いステートメントが引き続き発生することを示しています。現代のFortranは、最後と最後に&使用します。例えば、上記をより読みやすい形式で書くことができます:

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

共通ブロック

初期のFortran形式では、サブルーチンと関数からグローバル変数ストアを作成するための唯一のメカニズムは、 COMMONブロックメカニズムを使用することです。これにより、一連の変数を名前にして共有することができました。

名前付きの共通ブロックに加えて、空白(無名)の共通ブロックもあります。

空白の共通ブロックは次のように宣言できます

common i, j

名前付きブロックvariablesは次のように宣言できます

common /variables/ i, j

完全な例として、値を追加および削除できるルーチンで使用されるヒープストアを想像することができます。

       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

共通ステートメントを使用して、変数の型を暗黙的に宣言し、 dimension属性を指定することができます。この動作だけでは、しばしば混乱の原因になります。さらに、暗黙的なストレージの関連付けおよびプログラム単位にわたる繰り返し定義の要件により、共通のブロックを使用してエラーが発生しやすくなります。

最後に、共通ブロックは、そのブロックに含まれるオブジェクトの中で非常に制限されています。たとえば、共通ブロック内の配列は明示的なサイズでなければなりません。割り当て可能なオブジェクトは発生しない可能性があります。派生型はデフォルトの初期化を持つことはできません。

現代のFortranでは、変数の共有はモジュールの使用によって処理できます 。上記の例は次のように書くことができます:

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

名前付きブロックと空白の共通ブロックはわずかに異なる動作をします。注:

  • 名前付き共通ブロック内のオブジェクトを最初に定義することができます。ブランクコモンのオブジェクトは
  • 空白の共通ブロック内のオブジェクトは、共通ブロックにsave属性があるかのように動作します。ブロックがアクティブなプログラム単位のスコープ内にない場合、 save属性のない名前付き共通ブロック内のオブジェクトは未定義になることがあります

この後者の点は、現代のコードにおけるモジュール変数の挙動と対比させることができる。 Fortran 2008のすべてのモジュール変数は暗黙的に保存され、モジュールが有効範囲外になると未定義になりません。 Fortran 2008のモジュール変数(名前付き共通ブロック内の変数など)も、モジュールが有効範囲外になったときには未定義になります。

割り当てられたGOTO

割り当てられたGOTOは、ASSIGN文を使用してステートメントラベルが割り当てられる整数変数を使用します。

100 CONTINUE

...

ASSIGN 100 TO ILABEL

...


GOTO ILABEL

割り当てられたGOTOはFortran 90では廃止され、Fortran 95以降では削除されています。プロシージャ、内部プロシージャ、プロシージャポインタなどの機能を使用することで、現代のコードでは回避できます。

計算されたGOTO

計算されたGOTOは、整数式の値に従ってプログラムの分岐を可能にします。

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

scalar-integer-expressionが1に等しい場合、プログラムはステートメントラベルlabel_1で継続し、2の場合はlabel_2します。 1より小さいか、またはnより大きい場合、次の行にプログラムが続きます。

例:

ivar = 2

...

GOTO (10, 20, 30, 40) ivar

ステートメントラベル20にジャンプします。

この形式のgotoは、Fortran 95以降では廃止されており、 select case構文に取って代わられていselect case

割り当てられた書式指定子

Fortran 95より前には、入力または出力に割り当てられたフォーマットを使用することができました。検討する

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ステートメントは、ステートメントラベルを整数変数に割り当てます。この整数変数は、後でprintステートメントの書式指定子として使用されます。

このような書式指定子の割り当てはFortran 95で削除されました。代わりに、より現代的なコードでは、他の形式の実行フロー制御

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

または文字変数を書式指定子として使用できます

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

ステートメント関数

プログラムを検討する

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

print *, f(1)
end

ここで、 fはステートメント関数です。整数結果の型を持ち、1つの整数の仮引数をとります。 1

そのようなステートメント関数は、それが定義されているスコープ内に存在します。特に、変数とそのスコープ内でアクセス可能な名前付き定数にアクセスできます。

しかし、ステートメント関数には多くの制限があり、混乱を招く可能性があります(配列要素代入文のようなカジュアルな見方を参照)。重要な制限事項は次のとおりです。

  • 関数の結果と仮引数はスカラーでなければなりません
  • 仮引数は関数と同じスコープにあります
  • 文関数にはローカル変数がありません
  • 文の関数を実際の引数として渡すことはできません

ステートメント関数の主な利点は、内部関数

implicit none

print *, f(1)

contains

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

end

内部関数は、内部の副プログラムがそれ以上の内部副プログラムを含んでいないことに注意する価値があるかもしれませんが、上記の制限の対象ではありません(しかし、文機能を含むかもしれません)。

内部関数には独自のスコープがありますが、使用可能なホストの関連付けもあります。


1実際の古いコード例では、結果に明示的な型があっても、暗黙的に型指定されている文関数の仮引数を見るのは珍しいことではありません。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow