Fortran SAVE声明

时间:2010-05-23 19:26:40

标签: fortran fortran90

我已经阅读了(英特尔)语言参考文档中的save声明,但我无法理解它的作用。有人可以用简单的语言向我解释当save语句包含在模块中时它意味着什么吗?

3 个答案:

答案 0 :(得分:45)

原则上,当模块超出范围时,该模块的变量将变为未定义 - 除非使用SAVE属性声明它们,或者使用SAVE语句。 “未定义”意味着如果再次使用模块,则不允许依赖具有先前值的变量 - 当您重新访问模块时,它可能具有先前的值,或者可能不具有 - 不能保证。但是许多编译器不会为模块变量执行此操作 - 变量可能保留其值 - 编译器无法确定模块是否保留在范围内并且不值得可能模块变量被视为全局变量 - 但不依赖于它!为了安全起见,要么使用“保存”或“使用”主程序中的模块,以使其永远不会超出范围。

“save”在程序中也很重要,可以在子程序或函数的调用中存储“状态”(由@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 = ....

在此代码片段中,“counter”将报告子例程x的调用次数。虽然实际上在Fortran> = 90中可以省略“保存”,因为声明中的初始化意味着“保存”。

与模块情况相反,对于没有save属性或声明初始化的现代编译器,过程的局部变量在调用中丢失其值是正常的。因此,如果您在稍后的调用中尝试使用“var”,然后在该调用中重新定义它,则该值是未定义的,并且可能不是在先前调用该过程时计算的值。

这与许多FORTRAN 77编译器的行为不同,其中一些编译器保留了所有局部变量的值,即使这不是语言标准所要求的。一些旧的程序是依赖于这种非标准行为编写的 - 这些程序将在新的编译器上失败。许多编译器都可以选择使用非标准行为并“保存”所有局部变量。

LATER EDIT:使用代码示例进行更新,该示例显示应该具有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 为FALSE,因此 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

答案 1 :(得分:3)

通常,一旦执行离开当前过程,局部变量就会超出范围,因此在先前的调用中没有其值的“内存”。 SAVE是一种指定过程中的变量应该从一次调用到下一次调用的值的方法。当您想要在过程中存储状态时,它非常有用,例如,为了保持运行总计或维护变量的配置。

有一个good explanation here,有一个例子。

答案 2 :(得分:2)

简短的解释可能是:属性save表示必须在对同一子例程/函数的不同调用中保留变量的值。否则通常当您从子例程/函数返回时,“本地”变量将丢失其值,因为释放了存储这些变量的内存。如果您了解这种语言,它就像C中的static