这是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
繁荣!CALL SUBBAR(4)
将文字池中的4的值更改为5。然后您就纳闷为什么SUBBAZ
要假设将其传递为5而不是4
代码中实际编写的值。
较新版本的Fortran可以通过INTENT
将变量的声明为IN
或来缓解此问题,OUT
如果您将常量作为OUT
参数传递给您,则会出现错误(或至少是警告)。