Fortran SAVE заявление
Я читал о save
заявление в справочном документе по языку (Intel), но я не совсем понимаю, что он делает. Может ли кто-нибудь объяснить мне простым языком, что это значит, когда save
Выписка входит в модуль?
4 ответа
В принципе, когда модуль выходит из области видимости, переменные этого модуля становятся неопределенными - если они не объявлены с атрибутом SAVE или не используется инструкция SAVE. "Undefined" означает, что вы не можете полагаться на переменную, имеющую предыдущее значение, если вы снова используете модуль - у него может быть предыдущее значение при повторном доступе к модулю, или нет - нет гарантии, Но многие компиляторы не делают этого для переменных модуля - переменные, вероятно, сохраняют свои значения - компилятору не стоит пытаться выяснить, остается ли модуль в области действия или нет, и, вероятно, переменные модуля рассматриваются как глобальные переменные - но не полагайтесь на это! Для безопасности либо используйте "сохранить", либо "используйте" модуль из основной программы, чтобы он никогда не выходил за рамки.
"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", потому что инициализация в объявлении подразумевает "save".
В отличие от случая модуля, с современными компиляторами, без атрибута save или инициализации по объявлению, локальные переменные процедур обычно теряют свои значения при вызовах. Поэтому, если вы попытаетесь использовать "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 имеет значение 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
Обычно локальные переменные выходят из области видимости, когда выполнение покидает текущую процедуру, и поэтому не имеют "памяти" своего значения при предыдущих вызовах. SAVE
это способ указать, что переменная в процедуре должна сохранять свое значение от одного вызова до следующего. Это полезно, когда вы хотите сохранить состояние в процедуре, например, чтобы сохранить промежуточный итог или сохранить конфигурацию переменной.
Здесь есть хорошее объяснение с примером.
Публикация этого в качестве ответа MSB, потому что отсутствие форматирования в комментариях, вероятно, сделало бы свиной завтрак из всего этого:
Во-первых, спасибо за ответ, вы оба. Я ценю его.
Если я правильно понял;
subroutine save(j)
implicit none
integer :: i = 0, j
save i
i = i + j
write(*,*)i
end subroutine save
program test_save
implicit none
integer :: j
j = 1
call save(j)
call save(j)
end program test_save
если бы не оператор SAVE в вышеприведенном небольшом примере, переменная i (значение переменной) была бы "потеряна" после первого вызова подпрограммы save. Благодаря этому он сохраняет свое значение - в данном случае "1", и из-за этого он увеличивается до "2" во время второго вызова.
Я правильно понял? Может быть, рядом?
Краткое объяснение может быть: атрибут save
говорит, что значение переменной должно сохраняться при разных вызовах одной и той же подпрограммы / функции. В противном случае, как правило, когда вы возвращаетесь из подпрограммы / функции, "локальные" переменные теряют свои значения, поскольку освобождается память, в которой хранились эти переменные. Это как static
в C, если вы знаете этот язык.