原则上,当模块超出范围时,该模块的变量将变为未定义 - 除非使用 SAVE 属性声明它们,或者使用 SAVE 语句。 “未定义”意味着如果您再次使用该模块,则不允许您依赖具有先前值的变量 - 当您重新访问该模块时它可能具有先前的值,也可能不会 - 没有保证。但许多编译器不这样做module变量——变量可能保留它们的值——编译器不值得花精力去弄清楚模块是否仍在范围内,并且模块变量可能被视为全局变量——但不要依赖于此!为了安全起见,请在主程序中使用“保存”或“使用”模块,这样它就不会超出范围。
“保存”在过程中也很重要,用于存储子例程或函数调用之间的“状态”(由@ire_and_curses编写)——“第一次调用”初始化、计数器等。
subroutine my_sub (y)
integer :: var
integer, save :: counter = 0
logical, save :: FirstCall = .TRUE.
counter = counter + 1
write (*, *) counter
if (FirstCall) then
FirstCall = .FALSE.
....
end if
var = ....
etc.
在此代码片段中,“counter”将报告子例程 x 的调用次数。尽管实际上在 Fortran >=90 中可以省略“保存”,因为声明中的初始化意味着“保存”。
与模块情况相反,对于现代编译器,如果没有保存属性或声明初始化,过程的局部变量在调用过程中丢失其值是正常的。因此,如果您尝试在稍后的调用中使用“var”,然后在该调用中重新定义它,则该值是未定义的,并且可能不是在该过程的先前调用中计算的值。
这与许多 FORTRAN 77 编译器的行为不同,其中一些编译器保留所有局部变量的值,尽管语言标准并不要求这样做。一些旧程序是根据这种非标准行为编写的——这些程序在较新的编译器上将失败。许多编译器可以选择使用非标准行为并“保存”所有局部变量。
稍后编辑:使用显示的代码示例进行更新不正确使用应该具有 save 属性但没有的局部变量:
module subs
contains
subroutine asub (i, control)
implicit none
integer, intent (in) :: i
logical, intent (in) :: control
integer, save :: j = 0
integer :: k
j = j + i
if ( control ) k = 0
k = k + i
write (*, *) 'i, j, k=', i, j, k
end subroutine asub
end module subs
program test_saves
use subs
implicit none
call asub ( 3, .TRUE. )
call asub ( 4, .FALSE. )
end program test_saves
局部变数k子例程的值被故意滥用——在这个程序中,它在第一次调用时被初始化control是 TRUE,但在第二次调用时control是假的,所以k没有被重新定义。但没有保存属性k未定义,因此使用其值是非法的。
用gfortran编译程序,我发现k无论如何保留其价值:
i, j, k= 3 3 3
i, j, k= 4 7 7
使用 ifort 和积极的优化选项编译程序,k 失去了它的值:
i, j, k= 3 3 3
i, j, k= 4 7 4
使用 ifort 和调试选项,在运行时检测到问题!
i, j, k= 3 3 3
forrtl: severe (193): Run-Time Check Failure. The variable 'subs_mp_asub_$K' is being used without being defined