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)
归档时间: |
|
查看次数: |
48342 次 |
最近记录: |