- 締切済み
副プログラムの変数について
Fortranなのですが、以下のようなプログラムがあります。 call sub1 call sub1 end subroutine sub1 !save a write(*,*) a a=1.0 return end sub1というサブルーチンをメインから2回呼び出すだけです。そのサブルーチンの中の変数aですが、2回目に呼び出されたときに1回目に設定したa=1が保持されているようです。2回目の呼び出しで1回目に設定したa=1に対応した出力になっています。 Fortranはこのような動作をするのでしょうか。save aをコメントアウトしているのです。save aを指定したときだけそうなると思っていたのですが。cなどは細々とした設定ができるだろうと思います。このサンプルコードは実際にそうなっているという実験なのですが、どういう風に解釈したらいいでしょうか。〇〇保存属性とかです。昔からこうだったのでしょうか。使用したのはgfortran ver.9.3ですが。
- みんなの回答 (2)
- 専門家の回答
みんなの回答
- f272
- ベストアンサー率46% (8532/18263)
save aをコメントアウトしていれば,aの値は保証されません。 「2回目の呼び出しで1回目に設定したa=1に対応した出力になっています」というのはたまたまです。それを前提としたコーディングをしてはいけません。 $ gfortran -O xxx.f90 $ ./a 0.00000000 0.00000000 $ gfortran xxx.f90 $ ./a 0.00000000 1.00000000 $ gfortran -O2 xxx.f90 $ ./a 1.40129846E-45 1.40129846E-45 > 昔からこうだったのでしょうか 昔からコンパイラ依存でしたが,「ローカル変数は0に初期化して自動的にSAVE属性付き」にするコンパイラが幅を利かせていたので,それを前提とするプログラムがあったりします。
- asciiz
- ベストアンサー率70% (6825/9705)
初期化していない変数の値は『不定』です。 例えばC言語では、ローカル変数にはスタック領域が使われますが、変数宣言とはスタックポインタの現在地からのオフセットを定義するのみで、初期値が無ければそのメモリ内容は初期化しません。 プログラムが全く同じ流れで実行され、前回と今回が同じスタックポインタ位置で呼び出された場合、メモリ上に前の値が残っていることはあり得ます。 「あり得る」というだけで、「必ず前回の値になる」わけではありません。 2回の呼び出しの間に、さらに他のサブルーチンの呼び出しがあってスタック領域が使われれば、2回目の a の値は違ったものになるでしょう。 それだけであれば、「直前に呼び出した他の関数名」によって決まるようなことになってくるかもしれません。 ただし「割り込み処理」があることまで考えると、全く同じ流れであっても、スタックポインタの値が変わり、ローカル変数の実メモリ位置が変わってくることは大いにあり得ます。 そうすると、「大概は、サブルーチン○○を呼び出した後 a=xx になるが、たまにa=yy になっていることもある。」なんていう、プログラムとしてあるまじき事態になってしまいます。 ということで、当然の話なんですが、 『変数は初期化してから使いましょう』 という大原則が生まれます。 「初期化していない変数は0」←間違い 「初期化していない変数には前の値が残っている」←間違い まあオブジェクト指向言語では、必ず「コンストラクタ」があり、その中で変数用のメモリ確保と初期化を行うように書きますので、オブジェクトの宣言だけですぐに使い始められますが。 C言語やFortranなどの原始的な言語では、メモリ確保もその内容の初期化も、プログラマの責任となります。
お礼
回答ありがとうございます。プログラムの動作を実験によって確認することは危険である、ということですね。あるとき実際にそうなっていることと、いつも必ずそうなることが保証されるというのとは違うということで。プログラム作成の上で許されていることとは本に書いてあること、コンパイラの仕様書(これは保険の約款と同じか?)ということでしょうか。いずれにしても考えを改めることにします。