【发布时间】:2013-09-24 12:37:05
【问题描述】:
下面的程序试图犯一个常见的错误:修改函数参数, 而它最初是作为常量传递的。因此,通常,常数被存储 在目标代码的只读部分中,并且在运行时遇到访问冲突。
这正是 gfortran 发生的情况,优化 -O0 或 -O1(Windows 上的 gfortran 4.8.1)。 但它随着 -O2 消失,第二个 PRINT 显示值 100,和第一个一样。
通过查看汇编输出,我可以看到在 -O1 的情况下,函数 F 被优化了,但计算仍然在 A 的代码中完成,存储 117 会导致崩溃。使用 -O2,不进行任何计算,结果 (201) 作为常量包含在程序集输出中,并且永远不会存储值 117。
program bob
implicit none
call a(100)
contains
subroutine a(n)
integer :: n
print *, "In A:", f(n), n
print *, n
end subroutine
function f(n)
integer :: n, f
f = 2*n + 1
n = 117
end function
end program
标准是否接受这种行为?这是一个错误吗? 我的第一个想法是,这可能是优化器的一个错误(它不会做一些确实会产生影响的事情,因为修改后的值是在之后打印的)。但我知道,标准中未定义的行为通常会在实际运行时产生任何后果。
如果我将调用中的常量 100 替换为先前初始化为 100 的变量,编译器会产生预期的结果(第二个 PRINT 给我 117,具有任何优化级别)。
所以,也许优化器很聪明,在“常量”的情况下:由于代码会崩溃,打印不会发生,所以不需要值,所以优化出来,最后程序不会崩溃.但我还是觉得有点不解。
【问题讨论】:
-
我无法重现这个。使用 gfortran 4.6.3 和 ifort 13.1.3 时,我在
n=117行收到带有标志O1、O2和O3的段错误 -
对我来说结果相同。 FWIW Oracle
sunf90 -fast打印201 117 117 -
请注意,这可能与您使用内部过程有关。它们可能是内联的。
-
F 是内联的,而不是 A。但你是对的,当函数不是内部的时,我也总是遇到段错误。这很自然:当这些函数是内部函数时,只有主程序可以调用它们,所以编译器“知道”唯一的调用是用一个常量完成的,它可以以某种方式优化 n=117。当它们不是内部的时,程序可以与调用它们的其他函数链接,并使用真正的变量参数。
-
@Kyle。然后它在以后的版本中被引入。我正好使用 this 一个。