1

INTENTFortran のサブルーチン内の変数についていくつか質問があります。たとえば、数週間前、私は別の Fortran トピックに関する質問を投稿しました ( Fortran 90 では、テキスト ファイルに配列を行単位で書き込む良い方法は何ですか? )。返信の 1 つに、定義するコードが含まれていました。ticktockコマンド。これらは、コードの実行時間を計るのに役立つことがわかりました。tickと以下を貼り付けtockて、簡単な例で使用して、DOループの時間を計ります。

MODULE myintenttestsubs

  IMPLICIT NONE

CONTAINS

SUBROUTINE tick(t)
  INTEGER, INTENT(OUT) :: t
  CALL system_clock(t)
END SUBROUTINE tick

! returns time in seconds from now to time described by t
REAL FUNCTION tock(t)
  INTEGER, INTENT(IN) :: t
  INTEGER :: now, clock_rate

  CALL system_clock(now,clock_rate)

  tock = real(now - t)/real(clock_rate)
END FUNCTION tock

END MODULE myintenttestsubs

PROGRAM myintenttest
  USE myintenttestsubs
  IMPLICIT NONE
  INTEGER :: myclock, i, j
  REAL :: mytime

  CALL tick(myclock)

  ! Print alphabet 100 times
  DO i=1,100
     DO j=97,122
        WRITE(*,"(A)",ADVANCE="NO") ACHAR(j)
     END DO
  END DO

  mytime=tock(myclock)
  PRINT *, "Finished in ", mytime, " sec"
END PROGRAM myintenttest

これは、私の最初の質問につながります(以下の2番目の質問は、INTENTが明示的に指定されていないINTENTサブルーチンまたは関数の引数/変数に関するものです):

  1. タイマーを開始するには、 を書きます。CALL tick(myclock)ここmyclockで、 は整数です。サブルーチンのヘッダーはであるため、引数としてSUBROUTINE tick(t)ダミー整数を受け入れます。tただし、サブルーチン内でtは INTENT(OUT): が与えられますINTEGER, INTENT(OUT) :: t。どうすればいいの?私の素朴な仮定は、INTENT(OUT) は、この変数の値が変更され、サブルーチンからエクスポートされ、読み込まれないことを意味するということです。しかし、明らかtにサブルーチンに読み込まれています。整数myclockをサブルーチンに渡しています。tは INTENT(OUT) として宣言されているので、それもt入ってくるように見えるのはどうしてでしょうか?

  2. functiontock(t)では、整数変数nowclock_rateに明示的に INTENT が指定されていないことに気付きました。では、これらの変数のスコープは何ですか? 関数内nowclock_rate のみ表示されますか? (そのような構文はありませんが、INTENT(NONE) や INTENT(LOCAL) のようなものですか?) そして、これは関数ですが、サブルーチンにも同じことが当てはまりますか? サブルーチンを書いているときに、このような「一時的な」変数を宣言したい場合があります。これは、サブルーチン内でのみ見られる変数です (たとえば、最終出力の割り当て前のステップで入力を変更するため)。これは、指定された INTENT の欠如が達成するものですか?

テキスト ( Hahn による Fortran 90 テキスト)を調べたところ、彼は引数の意図について次のように簡単に説明しています。

引数の意図。 ダミー引数は、 intent属性で指定できます。つまり、それらを入力として使用するか、出力として使用するか、またはその両方として使用するかを指定できます。

SUBROUTINE PLUNK(X, Y, Z)
REAL, INTENT(IN) :: X
REAL, INTENT(OUT) :: Y
REAL, INTENT(INOUT) :: Z
...

インテントが IN の場合、サブプログラム内で仮引数の値が変更されていない可能性があります。

インテントが OUT の場合、対応する実引数は変数でなければなりません。のような呼び出し

CALL PLUNK(A, (B), C)

(B) は式であり、変数ではありません。

インテントが INOUT の場合、対応する実引数は再び変数でなければなりません。

仮引数に意図がない場合、実引数は変数または式である可能性があります。

すべての仮引数にインテントを指定することをお勧めします。特に、すべての関数の引数にはインテント IN が必要です。インテントは、INTENT(INOUT) X、Y、Z のように別のステートメントで指定することもできます。

上記のテキストは、引数/変数のスコープについて言及していないようです。主に、サブルーチンや関数内で引数/変数のを変更できるかどうかについて話しているようです。これは本当ですか?もしそうなら、INTENTに関するスコープについて何を仮定できますか?

4

3 に答える 3

3

あなたは意図についてはほとんど正しいですが、 tick() のセマンティクスについては間違っています。ティックルーチン

SUBROUTINE tick(t)
  INTEGER, INTENT(OUT) :: t
  CALL system_clock(t)
END SUBROUTINE tick

値を出力します渡されるインテントは、サブルーチンが呼び出されたときのシステム クロックの値です。次に、tock() はその値を使用して経過時間を計算し、その時間を入力として取得し、それを system_clock の現在の値と比較します。

REAL FUNCTION tock(t)
  INTEGER, INTENT(IN) :: t
  INTEGER :: now, clock_rate

  CALL system_clock(now,clock_rate)

  tock = real(now - t)/real(clock_rate)
END FUNCTION tock

スコープに関して: インテント (イン) とインテント (アウト) は、関数またはサブルーチンの引数リストで渡される変数である「ダミー引数」にのみ適用されます。たとえば、上記の例ではt、対応する仮引数が呼び出されるため、変数はローカルで として参照されますが、変数は必ずこのルーチンの外に存在します。

一方、変数nowclock_rateはローカル変数です。それらは、このルーチンのスコープ内にのみ存在します。intent渡された値を受け取ることも、値を渡すこともできないため、句を持たないことができます。それらは、このルーチンの範囲内にのみ存在します。

于 2011-08-08T21:38:03.693 に答える
2

コンパイラは、プログラマによるすべての間違いを検出する必要はありません。ほとんどのコンパイラは、デフォルトでより少ない間違いを検出し、コンパイル オプションによってより厳密になります。特定のオプションを使用すると、コンパイラは引数の意図の違反を検出し、診断メッセージを出力する可能性が高くなります。これは、バグをより迅速に検出するのに役立ちます。

インテントを宣言しない場合とインテント (inout) を宣言する場合の違いは微妙です。ダミーがインテント (inout) の場合、実引数は定義可能でなければなりません。定義できない引数の 1 つのケースは、"1.0" などの定数です。定数に代入しても意味がありません。これは、コンパイル時に診断できます。仮引数に意図が指定されていない場合、プロシージャーの実行中に実引数が割り当てられる場合、実引数は定義可能でなければなりません。これは、プログラム フロー (IF ステートメントなど) に依存する可能性があるため、診断がはるかに困難です。Fortran インテント (inout) とインテントの省略を参照してください。

于 2011-08-08T21:37:08.140 に答える
1

簡単な検索の後、次の質問を見つけました: Fortran のインテント (in、out、inout) の明示的な違いは何ですか?

そのことから、「インテントはコンパイラにとって単なるヒントであり、その情報を破棄して違反することができる」ということを学びました。-- 『ザ・グレイザー・ガイ』より

したがって、最初の質問に対する私の推測は次のとおりです。intent(OUT) 割り当ては、実際に変数を tick() サブルーチンに渡していることを確認するようにコンパイラに指示するだけです。次のように呼び出した場合:

call tick(10)

コンパイルエラーが発生します。上記の質問への回答では、意図の違いについても説明しています。

2 番目の質問については、引数とローカル変数を区別することが重要だと思います。サブルーチンの引数にインテントを割り当てることができます。引数にインテントを割り当てないと、コンパイラは、サブルーチンを正しく呼び出していることを確認するのに役立ちません。インテントを割り当てずにサブルーチンを誤って呼び出した場合 (たとえば、上記の tick() の呼び出し方法)、実行時にエラー (セグメンテーション フォールト) が発生したり、何らかの誤った動作が発生したりします。

サブルーチンには、一時変数として機能するローカル変数を含めることもできます。これらの変数はインテントを持つことができません。したがって、 tock サブルーチンのnow変数とclock_rate変数はローカル変数であり、インテントを持つべきではありません。それらにインテントを与えて、コンパイル時に何が起こるかを確認してください。意図がないという事実は、意図のない議論と同じことを意味するわけではありません。これら 2 つの変数はローカルであり、サブルーチンにのみ認識されます。意図のない引数は、サブルーチンとの間で情報をやり取りするために引き続き使用できます。インテント(inout)と同様のデフォルトのインテントが必要ですが、これを証明するドキュメントはありません。それが見つかったら、この回答を編集します。

編集: INTENT(OUT) 宣言に起因する問題の議論については、このページ も参照してください。これは高度なシナリオですが、文書化する価値があると思いました。

于 2011-08-08T20:35:51.930 に答える