Cosa significa dichiarare una variabile volatile?


9

Molti programmi di basso livello usano la parola chiave volatile per i tipi per la mappatura della memoria e simili, tuttavia sono un po 'confuso su ciò che REALMENTE fa in background. In altre parole, cosa significa quando il compilatore non "ottimizza" l'indirizzo di memoria?


1
Se stai leggendo la tua età da una volatilevariabile e dice 5, e la
rileggi

@ 5gon12eder, capisco che volatile significa che qualcosa è soggetto a cambiamenti rapidi e facili ma, come funziona? : S
Vikaton,

Inoltre, a seconda dei flag di compilazione, una variabile non volatile "potrebbe" apparire nel tuo debugger (supponiamo che tu stia usando codice C + Eclipse + gdb per esempio), come: "valore out ottimizzato" perché il valore della variabile è ora da qualche parte in un registro. Se non sai come utilizzare gli strumenti / funzionalità di debug del linguaggio assembly, dichiara semplicemente la tua variabile usando il modificatore volatile.

Risposte:


11

volatile significa che qualche altro processore o dispositivo I / O o qualcosa può cambiare la variabile da sotto di te.

Con una variabile ordinaria, i passaggi del tuo programma sono l'unica cosa che lo cambierà. Ad esempio, se leggi 5da una variabile e non la modifichi, conterrà comunque 5. Dato che puoi fare affidamento su questo, il tuo programma non deve impiegare il tempo per leggere nuovamente la variabile la prossima volta che vuoi usarla. Il compilatore C ++ è intelligente per generare codice che ricorda solo il 5.

Ma potresti leggerlo come 5, quindi forse il sistema carica i dati dal disco in quella memoria, cambiandoli in 500. Se vuoi che il tuo programma legga il nuovo valore 500, hai bisogno che il compilatore non sia troppo intelligente sull'uso del letto precedentemente letto 5. Devi dirlo per ricaricare il valore ogni volta. Questo è ciò che volatilefa.

Un'analogia per i bambini di 5 anni
Supponiamo che tu abbia messo un grande foglio di carta su un tavolo. In un angolo del foglio, di annotare il punteggio attuale di un gioco in corso, 3 to 4. Quindi vai sul lato opposto del tavolo e inizi a scrivere una storia sul gioco. Il tuo amico che sta guardando il gioco aggiorna il punteggio in quell'angolo man mano che il gioco procede. Cancella 3 to 4e scrive 3 to 5.

Quando vai a mettere il punteggio del gioco nella tua storia, puoi:

  1. Annota l'ultimo punteggio che hai letto, 3 to 4presumendo allegramente che non sia cambiato (o non preoccuparti se lo ha fatto), oppure
  2. Cammina intorno al lato opposto del tavolo per leggere il punteggio corrente (che sembra essere 3 to 5ora), e torna indietro. Ecco come volatileagisce una variabile.

11

volatile significa due cose:

  1. Il valore della variabile può cambiare senza che il tuo codice la cambi. Pertanto quando il compilatore legge il valore della variabile, esso può non supporre che è la stessa come l'ultima volta che è stato letto, o che è lo stesso come l'ultimo valore memorizzato, ma deve essere letto nuovamente.

  2. L'atto di memorizzare un valore in una variabile volatile è un "effetto collaterale" che può essere osservato dall'esterno, quindi al compilatore non è consentito rimuovere l'atto di memorizzare un valore; ad esempio se due valori sono memorizzati in una riga, il compilatore deve effettivamente memorizzare il valore due volte.

Come esempio:

i = 2; 
i = i; 

Il compilatore deve memorizzare il numero due, leggere la variabile i, memorizzare la variabile che ha letto in i.

Esiste un'altra situazione: se una funzione utilizza setjmpe quindi longjmpviene chiamata, tutte le variabili locali volatili della funzione avranno sicuramente l'ultimo valore memorizzato - questo non è il caso delle variabili locali non volatili.


Ci sono alcuni problemi sottili qui. Un problema sottile è che hai caratterizzato le letture volatili come una caratteristica della variabile quando in realtà sono una caratteristica di come si accede alla variabile . Se abbiamo la variabile ie il valore pi = &i, allora x = *pifa una lettura da i, ma quella lettura non è garantita per avere una semantica volatile.
Eric Lippert,

1
@EricLippert: se iviene dichiarato come volatile int iallora pideve essere dichiarato come volatile int *pi, nel qual caso *piè un accesso volatile, no?
Jon Purdy,

2

Spiegazione astratta
Sia C che C ++ hanno il concetto di una macchina astratta . Quando il codice utilizza il valore di una variabile, la macchina astratta dice che l'implementazione deve accedere al valore di quella variabile. Il codice del modulo statement_A; statement_B; statement_C;deve essere eseguito esattamente nell'ordine specificato. Le espressioni comuni a queste tre istruzioni devono essere ricalcolate ogni volta che si verificano.

Per le macchine astratte, data la sequenza delle affermazioni statement_A; statement_B; statement_C;, l'implementazione deve prima eseguire statement_Anella sua interezza, quindi statement_Be infine statement_C. L'implementazione non ricorda che hai assegnato ageil valore di 5. Ogni istruzione che fa riferimento agedeve invece accedere al valore di quella variabile.

Non sarebbe necessaria la volatileparola chiave se le implementazioni eseguissero rigorosamente il codice C o C ++ secondo le specifiche astratte della macchina. Le macchine astratte C e C ++ non hanno il concetto di registri, nessun concetto di sottoespressioni comuni e l'ordine di esecuzione è rigoroso.

Entrambe le lingue hanno anche regole as-if . Un'implementazione è conforme allo standard fintanto che l'implementazione si comporta come se avesse eseguito le cose secondo le specifiche astratte della macchina. Il compilatore può assumere che le variabili non volatili non cambino i valori tra le assegnazioni. Finché non infrange la as-ifregola, la sequenza statement_A; statement_B; statement_C;potrebbe essere implementata eseguendo parte di statement_C, quindi parte di statement_A, quindi tutto statement_B, quindi il resto statement_Ae infine il resto di statement_C.

Le regole as-if non si applicano alle volatilevariabili. Per quanto riguarda le volatilevariabili e le funzioni, un'implementazione deve fare esattamente ciò che gli hai detto di fare e esattamente nell'ordine in cui gli hai detto di fare le cose.

C'è un aspetto negativo nelle specifiche astratte della macchina: è lento. Un aspetto positivo di C e C ++ rispetto ad altre lingue è che sono abbastanza veloci. Questo non sarebbe il caso se il codice fosse eseguito per queste macchine astratte. Le regole as-if sono ciò che consente a C e C ++ di essere così veloci.

Risposta ELI5

cosa significa quando il compilatore non "ottimizza" l'indirizzo di memoria?

"Ottimizzare" un indirizzo di memoria è un concetto avanzato, qualcosa che non rientra nel regno delle capacità di un bambino di cinque anni. I bambini di cinque anni conformi faranno esattamente ciò che dici loro di fare, né più né meno. Con volatile, stai dicendo all'implementazione di agire come se fossero le cinque: nessun pensiero, nessuna ottimizzazione fantasiosa. Invece, l'implementazione deve fare esattamente ciò che il codice gli dice di fare.


1

(non) volatile è un suggerimento per il compilatore su come ottimizzare il codice (dal punto di vista del codice assembly generato):

  • non volatile significa che il compilatore corrente decide dove verrà posizionata la variabile o in che modo il valore della variabile viene trasferito a una subroutine
    • in un indirizzo di memoria fisso,
    • sullo stack [rispetto allo stackpointer corrente dei processori],
    • sull'heap [rispetto al basepointer corrente del processore],
    • in un registro del processore,
    • ...
  • volatile significa che il compilatore non può ottimizzare la variabile perché qualcos'altro al di fuori del controller main-cpu-s (cioè un io-processer separato) può cambiare questo valore.

0

Le risposte sembrano abbastanza coerenti ma mancano di un punto importante. Stai dicendo al compilatore che vuoi allocare spazio e per ogni accesso, leggi O SCRIVI, vuoi che esegua quell'accesso. Non vogliamo che ottimizzi tali accessi o quella variabile per qualche motivo.

Sì, uno dei motivi è che qualcun altro potrebbe cambiare quel valore per noi. Un altro motivo è che potremmo cambiare quel valore per qualcun altro. Che qualcun altro sia quello che lo cambia per noi o quello per cui lo stiamo cambiando potrebbe essere hardware / logica o software. Viene spesso utilizzato per definire gli accessi ai registri di controllo e di stato nei programmi embedded bare metal, scrivendo o leggendo dall'hardware. Oltre al software che parla al software spiegato in altre risposte.

Vedrai anche volatile usato per controllare quando e in quale ordine avvengono gli accessi, se stai cercando di cronometrare una sezione di codice e non usi volatile le variabili in questione (ora di inizio, ora di fine e differenza) devono essere solo calcolato verso la fine il compilatore è libero di spostare una delle misurazioni del tempo (non dove le abbiamo posizionate), non che non possa essere instabile ma l'esperienza lo dimostra meno probabile.

A volte, lo vedrai usato semplicemente per bruciare il tempo, un lampeggiante led elementare, il ciao mondo del bare metal, potrebbe usare un volatile per una variabile che conta un numero elevato solo per bruciare il tempo in cui l'occhio umano vede il led cambia stato. Esempi più avanzati quindi l'utilizzo di timer o altri eventi per perdere tempo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.