45

(Intel の) 言語リファレンス ドキュメントのステートメントについて読みましたsaveが、それが何をするのかよくわかりません。saveステートメントがモジュールに含まれている場合の意味を簡単な言葉で説明してもらえますか?

4

3 に答える 3

58

原則として、モジュールがスコープ外になると、そのモジュールの変数は、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
于 2010-05-23T21:47:13.593 に答える
5

通常、ローカル変数は、実行が現在のプロシージャを離れるとスコープ外になるため、以前の呼び出しでの値の「メモリ」がありません。SAVEプロシージャ内の変数が、ある呼び出しから次の呼び出しまでその値を維持する必要があることを指定する方法です。状態をプロシージャに保存する場合、たとえば、現在の合計を保持したり、変数の構成を維持したりする場合に便利です。

ここに例を挙げて、良い説明があります。

于 2010-05-23T19:47:51.827 に答える
3

簡単な説明は次のとおりです。属性saveは、同じサブルーチン/関数への異なる呼び出し間で変数の値を保持する必要があることを示しています。そうしないと、通常、サブルーチン/関数から戻るときに、変数が格納されていたメモリが解放されるため、「ローカル」変数の値が失われます。staticこの言語を知っていれば、C のようなものです。

于 2010-05-31T19:04:19.840 に答える