Я прочитал эту запись в справочной системе (Intel), но я не могу понять, что она делает. Может ли кто-то из непрофессионалов объяснить это мне, что это значит, когда он включен в модуль?
Заявление fortran SAVE
Ответ 1
В принципе, когда модуль выходит за пределы области видимости, переменные этого модуля становятся undefined - если они не объявлены с помощью атрибута SAVE или не используется оператор SAVE. "Undefined" означает, что вам не разрешается полагаться на переменную, имеющую предыдущее значение, если вы снова используете модуль - при повторном доступе к модулю может иметься предыдущее значение, или это может быть не так - без гарантии. Но многие компиляторы не делают этого для переменных модуля - переменные, вероятно, сохраняют свои значения - для компилятора не стоит пытаться выяснить, остается ли модуль в области видимости или нет, и, вероятно, переменные модуля рассматриваются как глобальные переменные - но не полагайтесь на это! Чтобы быть в безопасности, используйте "сохранить" или "использовать" модуль из основной программы, чтобы он никогда не выходил за рамки.
"сохранить" также важно в процедурах, чтобы хранить "состояние" через вызовы подпрограммы или функции (как написано @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 = ....
и др.
В этом фрагменте кода "счетчик" будет сообщать количество вызовов подпрограммы x. Хотя фактически в Fortran >= 90 можно опустить "сохранить", потому что инициализация в декларации подразумевает "сохранить".
В отличие от случая с модулем, с современными компиляторами, без атрибута сохранения или инициализации-на-декларации, для локальных переменных процедур нормально потерять свои значения во всех вызовах. Поэтому, если вы попытаетесь использовать "var" для более позднего вызова, прежде чем переопределять его в этом вызове, значение undefined и, вероятно, не будет значением, вычисленным при предыдущем вызове процедуры.
Это отличается от поведения многих компиляторов FORTRAN 77, некоторые из которых сохранили значения всех локальных переменных, хотя это не требовалось стандарту языка. Некоторые старые программы были написаны, опираясь на это нестандартное поведение - эти программы потерпят неудачу на новых компиляторах. Многие компиляторы имеют возможность использовать нестандартное поведение и "сохранять" все локальные переменные.
LATER EDIT: обновите пример кода, который показывает неправильное использование локальной переменной, которая должна иметь атрибут сохранения, но не имеет значения:
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 подпрограммы намеренно используется неправильно - в этой программе она инициализируется при первом вызове, так как управление имеет значение ИСТИНА, но во втором управлении вызовом FALSE, поэтому k не переопределяется. Но без атрибута save k это undefined, поэтому использование его значения является незаконным.
Компиляция программы с помощью 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
Ответ 2
Проводя это как ответ М.С.Б. потому что отсутствие форматирования в комментариях, вероятно, сделало бы свиной завтрак из всего:
Во-первых, спасибо за ответ, вы оба. Я ценю это.
Если я правильно понял,
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 в приведенном выше маленьком примере, переменная я (значение переменной) будет "потеряна" после первого вызова функции save. Благодаря этому он сохраняет значение "1" в этом случае, и из-за этого он увеличивается до "2" во время второго вызова.
Я исправился? Возможно, около?
Ответ 3
Обычно локальные переменные выходят из области действия, как только выполнение оставляет текущую процедуру, и поэтому не имеют "памяти" их значения при предыдущих вызовах. SAVE
- это способ указать, что переменная в процедуре должна поддерживать свое значение от одного вызова к следующему. Это полезно, когда вы хотите сохранить состояние в процедуре, например, чтобы сохранить общее количество или поддерживать переменную конфигурацию.
Здесь хорошее объяснение здесь, с примером.
Ответ 4
Коротким объяснением может быть: атрибут save
говорит, что значение переменной должно сохраняться при разных вызовах одной и той же подпрограммы/функции. В противном случае, когда вы возвращаетесь из подпрограммы/функции, "локальные" переменные теряют свои значения, так как освобождается память, в которой хранятся эти vars. Это похоже на static
в C, если вы знаете этот язык.