2010-05-23 13 views
30

He leído su entrada en la referencia del idioma (Intel), pero no puedo entender lo que hace. ¿Podría alguien en términos sencillos explicarme qué significa cuando está incluido en un módulo?fortran GUARDAR declaración

+0

Vea también http://stackoverflow.com/questions/2582409/are-local-variables-in-fortran-77-static-or-stack-dynamic/2583248 –

+7

Como complemento a las muy buenas respuestas que obtuvo, mi recomendación es: "nunca use guardar". Es una receta para desastres y hace que la rutina no sea segura y no apátrida. Puede haber razones para usar guardar, pero son muy, muy raros, y puede hacer lo mismo usando un estilo de programación o solución diferente. –

Respuesta

37

En principio, cuando un módulo sale fuera del alcance, las variables de ese módulo quedan indefinidas, a menos que se declaren con el atributo SAVE o se use una instrucción SAVE. "Indefinido" significa que no puede confiar en la variable que tiene el valor anterior si vuelve a utilizar el módulo; puede tener el valor anterior cuando vuelve a acceder al módulo, o puede que no lo haga; no hay garantía. . Pero muchos compiladores no hacen esto para las variables del módulo - las variables probablemente conservan sus valores - no vale la pena el esfuerzo para el compilador para determinar si un módulo permanece en el alcance o no y, probablemente, se tratan las variables del módulo como variables globales, ¡pero no confíes en eso! Para estar seguro, use "guardar" o "usar" el módulo del programa principal para que nunca se salga del alcance.

"salvar" es también importante en los procedimientos, para almacenar "estado" las invocaciones de la subrutina o función (escrita por @ire_and_curses) - inicializaciones "primera invocación", 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, "contador" informará el número de invocaciones de la subrutina x. Aunque en realidad en Fortran> = 90 uno puede omitir el "guardar" porque la inicialización en la declaración implica "guardar".

En contraste con el caso del módulo, con los compiladores modernos, sin el atributo guardar o la inicialización-en-una-declaración, es normal que las variables locales de procedimientos pierdan sus valores a través de invocaciones. Por lo tanto, si intenta utilizar "var" en una llamada posterior antes de redefinirla en esa llamada, el valor no está definido y probablemente no será el valor calculado en una invocación previa del procedimiento.

Esto es diferente del comportamiento de muchos compiladores de FORTRAN 77, algunos de los cuales conservan los valores de todas las variables locales, aunque esto no fue requerido por el estándar de lenguaje. Algunos programas antiguos se escribieron basándose en este comportamiento no estándar: estos programas fallarán en los compiladores más nuevos. Muchos compiladores tienen la opción de utilizar el comportamiento no estándar y "guardar" todas las variables locales.

de editar posteriormente: actualización con un ejemplo de código que muestra el uso incorrecto de una variable local que debe tener el atributo guardar, 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 

La variable local k de la subrutina es intencionalmente mal uso - en este programa se inicializa en la primera llamada desde control es VERDADERO, pero en la segunda llamada control es FALSO, por lo k no se redefine.Pero sin el atributo guardar k no está definido, por lo que el uso de su valor es ilegal.

Compilar el programa con gfortran, encontré que k conservó su valor de todos modos:

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

Compilar el programa con opciones ifort y optimización agresiva, k pierde su valor:

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

Usando ifort con opciones de depuración, ¡los problemas se detectaron en el 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 
+0

Quizás también valga la pena mencionar que es como la palabra clave "estática" en C. – MasterHD

+0

_ "use" el módulo del programa principal para que nunca salga de scope_, ahora veo la evidencia de por qué no he tenido problemas incluso escribiendo ni siquiera un solo 'SAVE' en mi programa! ¡Gracias! –

3

Normalmente, las variables locales salen del ámbito de aplicación una vez que la ejecución abandona el procedimiento actual, y por lo tanto no tienen 'memoria' de su valor en las invocaciones previas. 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 estado en un procedimiento, por ejemplo, para mantener un total acumulado o mantener la configuración de una variable.

Hay un good explanation here, con un ejemplo.

+0

Uhmm, ¿podrías dar un ejemplo de eso? Si entiendo correctamente, si declaro SAVE en un módulo, ¿sus variables no pueden cambiar valores en subrutinas? –

+0

@Friedrich Schwartz: No del todo. Aún puede establecer nuevos valores, pero si tuviera que inspeccionar el valor de la variable antes de configurarla, vería el último valor al que había establecido la variable. Sin 'SAVE ', verías' indefinido '. Trabajar a través de un simple ejemplo debería hacerlo más claro. –

4

Esto como una respuesta a M.S.B. porque la falta de formato en los comentarios probablemente haga un desayuno de cerdo fuera de todo:

En primer lugar, gracias por responder, a los dos. Lo aprecio.

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 declaración GUARDAR en el pequeño ejemplo anterior, la variable i (el valor de la variable) se "perdió" después de la primera llamada de subrutina guardar. Gracias a él, conserva su valor - "1" en este caso, y debido a ello, aumenta a "2" durante la segunda llamada.

¿Lo he acertado? Cerca de tal vez?

+4

Sí, la instrucción SAVE hace que la variable i conserve su valor. Una sutil es que en este ejemplo, en Fortran 90, la declaración de guardado es opcional: "guardar" se aplica automáticamente porque "i" se inicializa en una declaración. La declaración de guardar sería obligatoria en FORTRAN 77. –

2

Una breve explicación podría ser: el atributo save dice que el valor de una variable debe conservarse en 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 se libera la memoria donde se almacenaron esos valores. Es como static en C, si conoce este idioma.