下面的程序试图犯一个常见的错误:修改函数参数,而它最初是作为常量传递的。因此,通常,常量存储在目标代码的只读部分中,并且在运行时会发生访问冲突。
这正是 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,具有任何优化级别)。
所以,也许优化器非常聪明,在“恒定”的情况下:由于代码会崩溃,打印不会发生,所以不需要值,所以优化,最后程序不会崩溃。但我还是觉得有点令人费解。