(Intel の) 言語リファレンス ドキュメントのステートメントについて読みましたsave
が、それが何をするのかよくわかりません。save
ステートメントがモジュールに含まれている場合の意味を簡単な言葉で説明してもらえますか?
3 に答える
原則として、モジュールがスコープ外になると、そのモジュールの変数は、SAVE 属性で宣言されていない限り、または SAVE ステートメントが使用されていない限り、未定義になります。「未定義」とは、モジュールを再度使用する場合に、以前の値を持つ変数に依存することが許可されていないことを意味します。モジュールに再度アクセスしたときに以前の値を持つ場合もあれば、そうでない場合もあります。保証はありません。 . しかし、多くのコンパイラはモジュール変数に対してこれを行いません- 変数はおそらくそれらの値を保持します - モジュールがスコープ内に残っているかどうかをコンパイラが判断するのは価値がなく、おそらくモジュール変数はグローバルとして扱われます変数 -- しかし、それに依存しないでください! 安全のために、「保存」または「使用」のいずれかを使用してください
「保存」は、サブルーチンまたは関数の呼び出し全体で「状態」を保存するために、手順でも重要です(@ire_and_cursesによって記述されています)-「最初の呼び出し」の初期化、カウンターなど。
subroutine my_sub (y)
integer :: var
integer, save :: counter = 0
logical, save :: FirstCall = .TRUE.
counter = counter + 1
write (*, *) counter
if (FirstCall) then
FirstCall = .FALSE.
....
end if
var = ....
等
このコード フラグメントでは、「counter」はサブルーチン x の呼び出し回数を報告します。実際には Fortran >=90 では、宣言の初期化が「保存」を意味するため、「保存」を省略できます。
モジュールの場合とは対照的に、最新のコンパイラでは、save 属性または宣言時の初期化がない場合、プロシージャのローカル変数が呼び出し間で値を失うのは正常です。したがって、その呼び出しで「var」を再定義する前に、その呼び出しで「var」を使用しようとすると、値は未定義になり、おそらくプロシージャの以前の呼び出しで計算された値にはなりません。
これは、多くの FORTRAN 77 コンパイラの動作とは異なります。一部のコンパイラはすべてのローカル変数の値を保持していましたが、これは言語標準では要求されていませんでした。一部の古いプログラムは、この非標準の動作に依存して作成されました。これらのプログラムは、新しいコンパイラでは失敗します。多くのコンパイラには、非標準の動作を使用してすべてのローカル変数を「保存」するオプションがあります。
LATER EDIT: save属性を持つべきであるがそうでないローカル変数の誤った使用法を示すコード例で更新します。
module subs
contains
subroutine asub (i, control)
implicit none
integer, intent (in) :: i
logical, intent (in) :: control
integer, save :: j = 0
integer :: k
j = j + i
if ( control ) k = 0
k = k + i
write (*, *) 'i, j, k=', i, j, k
end subroutine asub
end module subs
program test_saves
use subs
implicit none
call asub ( 3, .TRUE. )
call asub ( 4, .FALSE. )
end program test_saves
サブルーチンのローカル変数kは意図的に誤用されています。このプログラムでは、制御が TRUE であるため最初の呼び出しで初期化されますが、2 番目の呼び出しでは制御が FALSE であるため、kは再定義されません。ただし、save 属性がない場合、 kは定義されていないため、その値を使用することはできません。
プログラムを gfortran でコンパイルすると、kがとにかくその値を保持していることがわかりました。
i, j, k= 3 3 3
i, j, k= 4 7 7
ifort と積極的な最適化オプションを使用してプログラムをコンパイルすると、k の値が失われます。
i, j, k= 3 3 3
i, j, k= 4 7 4
デバッグ オプションを指定して ifort を使用すると、実行時に問題が検出されました。
i, j, k= 3 3 3
forrtl: severe (193): Run-Time Check Failure. The variable 'subs_mp_asub_$K' is being used without being defined
通常、ローカル変数は、実行が現在のプロシージャを離れるとスコープ外になるため、以前の呼び出しでの値の「メモリ」がありません。SAVE
プロシージャ内の変数が、ある呼び出しから次の呼び出しまでその値を維持する必要があることを指定する方法です。状態をプロシージャに保存する場合、たとえば、現在の合計を保持したり、変数の構成を維持したりする場合に便利です。
ここに例を挙げて、良い説明があります。
簡単な説明は次のとおりです。属性save
は、同じサブルーチン/関数への異なる呼び出し間で変数の値を保持する必要があることを示しています。そうしないと、通常、サブルーチン/関数から戻るときに、変数が格納されていたメモリが解放されるため、「ローカル」変数の値が失われます。static
この言語を知っていれば、C のようなものです。