Это было непреднамеренным побочным эффектом стратегии оценки вызовов функций FORTRAN в сочетании с ошибочной оптимизацией компилятора.
FORTRAN II представил пользовательские функции и подпрограммы с аргументами, передаваемыми по ссылке . (Почему, я не знаю. Вероятно, это было более эффективно, чем передача по стоимости на оборудовании IBM того времени.)
Обычно передача по ссылке означает, что вы должны передать значение l (например, переменную) вместо значения r. Но дизайнеры 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
Boom! CALL SUBBAR(4)
изменил значение 4 в литеральном пуле на 5. И тогда вам остается только удивляться, почему SUBBAZ
вы предполагаете, что вы передали ему 5 вместо того, что 4
вы фактически написали в коде.
Более новые версии Fortran смягчают эту проблему, позволяя вам объявить INTENT
переменную как IN
или или OUT
выдавая ошибку (или, по крайней мере, предупреждение), если вы передаете константу в качестве OUT
параметра.