Подтвердить что ты не робот

Заявление fortran SAVE

Я прочитал эту запись в справочной системе (Intel), но я не могу понять, что она делает. Может ли кто-то из непрофессионалов объяснить это мне, что это значит, когда он включен в модуль?

4b9b3361

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