2010-05-23 13 views
30

Ho letto la sua voce nella lingua di riferimento (Intel), ma non riesco a capire cosa faccia. Qualcuno potrebbe, in parole povere, spiegarmelo, cosa significa quando è incluso in un modulo?fortran SAVE statement

+0

Vedere anche http://stackoverflow.com/questions/2582409/are-local-variables-in-fortran-77-static-or-stack-dynamic/2583248 –

+7

Come complemento alle ottime risposte che hai ottenuto, la mia raccomandazione è: "non usare mai salvare". È una ricetta per il disastro e rende la routine non thread safe e non apolidi. Ci possono essere motivi per usare save, ma sono molto, molto rari, e puoi fare lo stesso usando uno stile di programmazione o una soluzione diversa. –

risposta

37

In principio quando un modulo diventa fuori campo, le variabili di quel modulo diventano indefinite - a meno che non siano dichiarate con l'attributo SAVE, o venga utilizzata un'istruzione SAVE. "Non definito" significa che non ti è permesso fare affidamento sulla variabile che ha il valore precedente se usi di nuovo il modulo - potrebbe avere il valore precedente quando riaccedi al modulo, o potrebbe non farlo - non c'è garanzia . Ma molti compilatori non lo fanno per il modulo variabili - le variabili probabilmente mantengono i loro valori - non vale la pena per il compilatore di capire se un modulo rimane nell'ambito o meno e probabilmente le variabili del modulo sono trattate come variabili globali - ma non fare affidamento su questo! Per sicurezza, usa "salva" o "usa" il modulo dal programma principale in modo che non diventi mai fuori portata.

"salvare" è importante anche nelle procedure, per memorizzare "stato" attraverso invocazioni della subroutine o di una funzione (come scritto da @ire_and_curses) - inizializzazione "prima invocazione", contatori, ecc

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

ecc.

In questo frammento di codice, "contatore" riporterà il numero di invocazioni della subroutine x. Sebbene in realtà in Fortran> = 90 si può omettere il "salvataggio" perché l'inizializzazione nella dichiarazione implica "salva".

In contrasto con il caso del modulo, con i compilatori moderni, senza l'attributo di salvataggio o l'inizializzazione su una dichiarazione, è normale che le variabili locali delle procedure perda i loro valori attraverso invocazioni. Pertanto, se si tenta di utilizzare "var" in una chiamata successiva prima di ridefinirla in tale chiamata, il valore non è definito e probabilmente non sarà il valore calcolato su una precedente chiamata della procedura.

Questo è diverso dal comportamento di molti compilatori FORTRAN 77, alcuni dei quali mantenevano i valori di tutte le variabili locali, anche se questo non era richiesto dallo standard di lingua. Alcuni vecchi programmi sono stati scritti facendo affidamento su questo comportamento non standard - questi programmi non funzioneranno con i nuovi compilatori. Molti compilatori hanno un'opzione per usare il comportamento non standard e "salvare" tutte le variabili locali.

Successivamente modificare: aggiornamento con un esempio di codice che mostra corretto utilizzo di una variabile locale che dovrebbe avere l'attributo salvataggio ma non:

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 

variabile locale k della subroutine è volutamente abusato - in questo programma è inizializzato nella prima chiamata dal il controllo è VERO, ma sulla seconda chiamata il controllo è FALSE, quindi k non viene ridefinito.Ma senza l'attributo di salvataggio k non è definito, quindi l'utilizzo del suo valore è illegale.

Compilare il programma con gfortran, ho scoperto che k mantenuto il suo valore in ogni caso:

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

Compilare il programma con le opzioni ifort e ottimizzazione aggressiva, k ha perso il suo valore:

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

Usando ifort con le opzioni di debug, i problemi sono stati rilevati in fase di esecuzione!

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

Forse vale la pena ricordare che è come la parola chiave "statica" in C. – MasterHD

+0

_ "usa" il modulo dal programma principale in modo che non vada mai fuori portata_, ora vedo l'ovvietà nel motivo per cui non ho avuto problemi nemmeno a scrivere nemmeno un singolo 'SAVE' nel mio programma! Grazie! –

3

Normalmente, le variabili locali escono dall'ambito di applicazione una volta che l'esecuzione ha abbandonato la procedura corrente e quindi non ha memoria del loro valore nelle chiamate precedenti. SAVE è un modo per specificare che una variabile in una procedura deve mantenere il suo valore da una chiamata alla successiva. È utile quando si desidera memorizzare lo stato in una procedura, ad esempio per mantenere un totale parziale o mantenere la configurazione di una variabile.

C'è un good explanation here, con un esempio.

+0

Uhmm, potresti fare un esempio? Se ho capito bene, se dichiaro SALVA in un modulo, le sue variabili non possono cambiare i valori nelle subroutine? –

+0

@Friedrich Schwartz: Non proprio. Puoi ancora impostare nuovi valori, ma se dovessi controllare il valore della variabile prima di impostarla, vedresti l'ultimo valore a cui hai impostato la variabile. Senza 'SAVE', vedresti 'indefinito'. Lavorare attraverso un semplice esempio dovrebbe renderlo più chiaro. –

4

Pubblicare come risposta a M.S.B. perché la mancanza di formattazione nei commenti sarebbe probabilmente fare colazione di maiale fuori dal tutto:

Innanzitutto, grazie per aver risposto, entrambi. Lo apprezzo.

Se ho capito bene;

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 

Se non fosse per l'istruzione SAVE nel piccolo esempio di cui sopra, la variabile i (il valore della variabile) sarebbe "perso" dopo la prima chiamata di salvare subroutine. Grazie ad esso, mantiene il suo valore - "1" in questo caso, e per questo aumenta a "2" durante la seconda chiamata.

Ho capito bene? Vicino forse?

+4

Sì, l'istruzione SAVE fa sì che la variabile i mantenga il suo valore. Uno di questi è che in questo esempio, in Fortran 90, l'istruzione save è facoltativa: "save" si applica automaticamente perché "i" è inizializzato in una dichiarazione. La dichiarazione di salvataggio sarebbe obbligatoria in FORTRAN 77. –

2

Una breve spiegazione potrebbe essere: l'attributo save dice che il valore di una variabile deve essere conservato tra diverse chiamate alla stessa subroutine/funzione. Altrimenti normalmente quando si ritorna da una subroutine/funzione, le variabili "locali" perdono i loro valori poiché la memoria in cui sono stati memorizzati quei vars è stata rilasciata. È come static in C, se conosci questa lingua.