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, если вы знаете этот язык.

Другие вопросы по тегам