Fortran SAVE声明

Fri*_*rtz 38 fortran fortran90

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

M. *_* B. 47

原则上,当模块超出范围时,该模块的变量将变为未定义 - 除非它们使用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 = ....
Run Code Online (Sandbox Code Playgroud)

等等

在此代码片段中,"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
Run Code Online (Sandbox Code Playgroud)

故意误用子程序的局部变量k - 在该程序中,由于控制为TRUE,因此在第一次调用中初始化,但在第二次调用控制为FALSE时,因此不重新定义k.但是如果没有保存属性k是未定义的,那么使用它的值是非法的.

使用gfortran编译程序时,我发现k仍保留其值:

 i, j, k=           3           3           3
 i, j, k=           4           7           7
Run Code Online (Sandbox Code Playgroud)

使用ifort和积极优化选项编译程序时,k失去了它的值:

 i, j, k=           3           3           3
 i, j, k=           4           7           4
Run Code Online (Sandbox Code Playgroud)

使用带有调试选项的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
Run Code Online (Sandbox Code Playgroud)

  • 也许还值得一提的是,它就像C语言中的“ static”关键字一样。 (2认同)

ire*_*ses 7

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

这里有一个很好的解释,还有一个例子。