これは、誤ったコンパイラ最適化と組み合わせた、FORTRANの関数呼び出し評価戦略の意図しない副作用でした。
FORTRAN II は、参照渡しの引数を持つユーザー定義関数とサブルーチンを導入しました。(なぜかわかりません。当時のIBMハードウェアでの値渡しよりもおそらく効率的でした。)
通常、参照渡しとは、r値の代わりにl値(変数など)を渡す必要があることを意味します。しかし、FORTRANの設計者は有用であり、とにかく引数としてr値を渡すことにしました。コンパイラーが変数を自動的に生成します。だから、あなたが書いた場合:
CALL SUBFOO(X + Y, 4)
コンパイラはこれをバックグラウンドで次のようなものに変換します
TEMP1 = X + Y
TEMP2 = 4
CALL SUBFOO(TEMP1, TEMP2)
「リテラルプール」と呼ばれる一般的なコンパイラ最適化もありました。これは、同じ数値定数の複数のインスタンスを同じ自動生成変数に統合します。(Cファミリーのいくつかの言語では、文字列リテラルにこれが必要です。)
CALL SUBBAR(4)
CALL SUBBAZ(4)
これはあたかもそれがあったかのように扱われます
FOUR = 4
CALL SUBBAR(FOUR)
CALL SUBBAZ(FOUR)
これは、パラメータの値を変更するサブプログラムを作成するまで、完全に合理的なことのように思えます。
SUBROUTINE SUBBAR(X)
!...lots of code...
X = 5
!...lots of code...
END SUBROUTINE SUBBAR
ブーム!CALL SUBBAR(4)
リテラルプールの4の値を5に変更しました。そして、実際にコードで記述したのSUBBAZ
ではなく、なぜ5を渡したと仮定しているのか疑問に思わ4
れます。
Fortranの新しいバージョンでINTENT
は、変数のをIN
またはとして宣言しOUT
、定数をOUT
パラメーターとして渡すとエラー(または少なくとも警告)を与えることにより、この問題を軽減します。