Fortran SAVE statement


He leído acerca de la declaración save en el documento de referencia de lenguaje (de Intel), pero no puedo entender lo que hace. ¿Podría alguien explicarme en un lenguaje sencillo lo que significa cuando la instrucción save se incluye en un módulo ?

Author: High Performance Mark, 2010-05-23

4 answers

En principio, cuando un módulo sale del ámbito, las variables de ese módulo se vuelven indefinidas unless a menos que se declaren con el atributo SAVE, o se use una instrucción SAVE. "Indefinido" significa que no se le permite confiar en que la variable tenga el valor anterior si vuelve a usar el módulo might podría tener el valor anterior cuando vuelva a acceder al módulo, o podría no -- no hay garantía. Pero muchos compiladores no hacen esto para module variables the las variables probablemente conserve sus valores't no vale la pena el esfuerzo para que el compilador averigüe si un módulo permanece en el ámbito o no y probablemente las variables del módulo se traten como variables globales! ¡pero no confíe en eso! Para estar seguro, use "guardar" o "usar" el módulo del programa principal para que nunca salga del alcance.

"guardar" también es importante en los procedimientos, para almacenar "estado" a través de invocaciones de la subrutina o función (como escrito por @ire_and_curses) first " primero invocación" inicializaciones, contadores, etc.

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 = ....

Etc.

En este fragmento de código, "counter" reportará el número de invocaciones de subrutina x. Aunque en Fortran >=90 se puede omitir el "save" porque la inicialización en la declaración implica "save".

En contraste con el caso del módulo, con compiladores modernos, sin el atributo save o inicialización en una declaración, es normal que las variables locales de los procedimientos pierdan sus valores a través de invocación. Así que si intenta usar " var " en una llamada posterior antes de redefinirla en esa llamada, el valor es indefinido y probablemente no será el valor calculado en una invocación anterior del procedimiento.

Esto es diferente del comportamiento de muchos compiladores FORTRAN 77, algunos de los cuales retuvieron los valores de todas las variables locales, a pesar de que esto no era requerido por el estándar del lenguaje. Algunos programas antiguos fueron escritos basándose en este comportamiento no estándar these estos programas fallarán en los nuevos compiladores. Muchos compiladores tienen la opción de usar el comportamiento no estándar y "guardar" todas las variables locales.

EDICIÓN POSTERIOR: actualización con un ejemplo de código que muestra uso incorrecto de una variable local que debería tener el atributo save pero no:

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

Variable Local k de la subrutina es intencionalmente mal utilizado, en este programa se inicializa en la primera llamada desde control es CIERTO, pero en la segunda convocatoria control es FALSE, así que k no está redefinido. Pero sin el atributo save k es indefinido, por lo que usar su valor es ilegal.

Compilando el programa con gfortran, encontré que k retuvo su valor de todos modos:

 i, j, k=           3           3           3
 i, j, k=           4           7           7

Compilando el programa con ifort y opciones de optimización agresivas, k perdió su valor:

 i, j, k=           3           3           3
 i, j, k=           4           7           4

Utilizando ifort con opciones de depuración, los problemas se detectaron en tiempo de ejecución!

 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
 42
Author: M. S. B.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-24 02:29:16

Publicar esto como una respuesta a M. S. B. porque la falta de formato en los comentarios probablemente haría que el desayuno de un cerdo fuera de todo:

Primero, gracias por responder, ambos. Te lo agradezco.

Si entendí bien;

  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

Si no fuera por la instrucción SAVE en el pequeño ejemplo anterior, la variable i (el valor de la variable) se "perdería" después de la primera llamada de la subrutina save. Gracias a él, conserva su valor- " 1 " en este caso, y debido a ello, aumenta a "2" durante la segunda llamada.

¿Lo he entendido bien ? ¿Cerca de tal vez ?

 4
Author: Friedrich Schwartz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-23 22:12:46

Normalmente, las variables locales salen del ámbito una vez que la ejecución abandona el procedimiento actual, y por lo tanto no tienen 'memoria' de su valor en invocaciones anteriores. SAVE es una forma de especificar que una variable en un procedimiento debe mantener su valor de una llamada a la siguiente. Es útil cuando desea almacenar el estado en un procedimiento, por ejemplo, para mantener un total en ejecución o mantener la configuración de una variable.

Hay una buena explicación aquí, con un ejemplo.

 3
Author: ire_and_curses,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-23 19:53:25

Una breve explicación podría ser: el atributo save dice que el valor de una variable debe ser preservado a través de diferentes llamadas a la misma subrutina/función. De lo contrario, normalmente cuando regresa de una subrutina/función, las variables "locales" pierden sus valores ya que la memoria donde se almacenaron esos vars se libera. Es como static en C, si conoces este idioma.

 2
Author: ShinTakezou,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-31 19:04:19