Differenza tra const e const volatile


90

Se dichiariamo una variabile come volatileogni volta che il nuovo valore viene aggiornato
Se dichiariamo una variabile come constallora il valore di quella variabile non saràmodificato

Allora a const volatile int temp;
cosa serve dichiarare la variabile tempcome sopra?
Cosa succede se dichiariamo come const int temp?


Non const volatile int temp;useresti nell'ambito del blocco (cioè all'interno { }), non ha alcuna utilità lì.
MM

Risposte:


149

Un oggetto contrassegnato come const volatilenon potrà essere modificato dal codice (verrà generato un errore a causa del constqualificatore) - almeno attraverso quel particolare nome / puntatore.

La volatileparte del qualificatore indica che il compilatore non può ottimizzare o riordinare l'accesso all'oggetto.

In un sistema integrato, questo viene in genere utilizzato per accedere ai registri hardware che possono essere letti e aggiornati dall'hardware, ma non ha senso scrivere (o potrebbe essere un errore in cui scrivere).

Un esempio potrebbe essere il registro di stato per una porta seriale. Vari bit indicheranno se un carattere è in attesa di essere letto o se il registro di trasmissione è pronto per accettare un nuovo carattere (cioè, è vuoto). Ogni lettura di questo registro di stato potrebbe risultare in un valore diverso a seconda di cos'altro si è verificato nell'hardware della porta seriale.

Non ha senso scrivere nel registro di stato (a seconda della specifica specifica dell'hardware), ma è necessario assicurarsi che ogni lettura del registro risulti in una lettura effettiva dell'hardware - utilizzando un valore memorizzato nella cache da una lettura precedente ha vinto ' t informarti sui cambiamenti nello stato dell'hardware.

Un rapido esempio:

Se questi puntatori non sono stati contrassegnati come tali volatile, potrebbero verificarsi un paio di problemi:

  • il test del ciclo while potrebbe leggere il registro di stato solo una volta, poiché il compilatore potrebbe presumere che qualunque cosa indicasse non cambierebbe mai (non c'è nulla nel test del ciclo while o nel ciclo stesso che potrebbe cambiarlo). Se sei entrato nella funzione quando non c'erano caratteri in attesa nell'hardware UART, potresti finire in un ciclo infinito che non si è mai fermato anche quando un carattere è stato ricevuto.
  • la lettura del registro di ricezione potrebbe essere spostata dal compilatore prima del ciclo while - di nuovo perché non c'è nulla nella funzione che indichi che *recv_regè cambiato dal ciclo, non c'è motivo per cui non possa essere letto prima di entrare nel ciclo.

I volatilequalificatori assicurano che queste ottimizzazioni non vengano eseguite dal compilatore.


5
+1 per la spiegazione. E ho una domanda: che dire dei metodi volatili const? Se ho una classe, a cui si accede da molti thread (sebbene l'accesso sia sincronizzato con mutex), anche i miei metodi const devono essere volatili (poiché alcune variabili potrebbero essere modificate da altri thread)
Sasa

41
  • volatile dirà al compilatore di non ottimizzare il codice relativo alla variabile, di solito quando sappiamo che può essere modificata da "fuori", ad esempio da un altro thread.
  • const dirà al compilatore che è proibito al programma modificare il valore della variabile.
  • const volatileè una cosa molto speciale che probabilmente vedrai usata esattamente 0 volte nella tua vita (tm). Come prevedibile, significa che il programma non può modificare il valore della variabile, ma il valore può essere modificato dall'esterno, quindi non verranno eseguite ottimizzazioni sulla variabile.

12
Avrei pensato che le volatilevariabili siano di solito ciò che accade quando inizi a fare confusione con l'hardware, non con altri thread. Dove ho visto const volatileusato è in cose come i registri di stato mappati in memoria o simili.
SOLO LA MIA OPINIONE corretta

2
Certo, hai perfettamente ragione, il multithreading è solo un esempio, ma non l'unico :).
mingos

26
Se lavori con sistemi embedded lo vedrai molto spesso.
Daniel Grillo

29

Non è perché la variabile è const che potrebbe non essere cambiata tra due punti di sequenza.

La costanza è una promessa che fai di non modificare il valore, non che il valore non verrà modificato.


10
Più uno per sottolineare che i constdati non sono "costanti".
Bogdan Alexandru

7

Avevo bisogno di usarlo in un'applicazione incorporata in cui alcune variabili di configurazione si trovano in un'area della memoria flash che può essere aggiornata da un bootloader. Queste variabili di configurazione sono 'costanti' durante il runtime, ma senza il qualificatore volatile il compilatore ottimizzerebbe qualcosa del genere ...

... precalcolando il valore della costante e utilizzando un'istruzione di assemblaggio immediata, o caricando la costante da una posizione vicina, in modo che qualsiasi aggiornamento al valore CANID originale nell'area flash di configurazione venga ignorato. CANID deve essere const volatile.


7

In C, conste volatilesono qualificatori di tipo e questi due sono indipendenti.

Fondamentalmente, constsignifica che il valore non è modificabile dal programma.

E volatilesignifica che il valore è soggetto a variazione improvvisa (possibilmente dall'esterno del programma).

In effetti, lo standard C fornisce un esempio di una dichiarazione valida che è sia conste volatile. L'esempio è:

extern const volatile int real_time_clock;

dove real_time_clockpuò essere modificabile dall'hardware, ma non può essere assegnato, incrementato o decrementato.

Quindi dovremmo già trattare conste volatileseparatamente. Questi qualificatori tipo possono essere applicati a struct, union, enume typedefpure.


5

constsignifica che la variabile non può essere modificata dal codice c, non che non può cambiare. Significa che nessuna istruzione può scrivere sulla variabile, ma il suo valore potrebbe comunque cambiare.

volatilesignifica che la variabile può cambiare in qualsiasi momento e quindi non è possibile utilizzare valori memorizzati nella cache; ogni accesso alla variabile deve essere eseguito al suo indirizzo di memoria.

Poiché la domanda è contrassegnata come "incorporata" e supponendo che tempsia una variabile dichiarata dall'utente, non un registro relativo all'hardware (poiché questi sono solitamente gestiti in un file .h separato), si consideri:

Un processore integrato che ha sia una memoria dati (RAM) volatile di lettura-scrittura che una memoria dati non volatile di sola lettura, ad esempio una memoria FLASH nell'architettura von-Neumann, dove i dati e lo spazio del programma condividono un bus di dati e indirizzi comune.

Se si dichiara const tempdi avere un valore (almeno se diverso da 0), il compilatore assegnerà la variabile ad un indirizzo nello spazio FLASH, perché anche se fosse assegnata ad un indirizzo RAM ha comunque bisogno di memoria FLASH per memorizzare il valore iniziale della variabile, rendendo l'indirizzo RAM uno spreco di spazio poiché tutte le operazioni sono di sola lettura.

Conseguentemente:

int temp;è una variabile memorizzata nella RAM, inizializzata a 0 all'avvio (cstart), possono essere utilizzati valori memorizzati nella cache.

const int temp;è una variabile memorizzata in FLASH (read-ony), inizializzata a 0 al momento del compilatore, possono essere usati valori memorizzati nella cache.

volatile int temp; è una variabile memorizzata nella RAM, inizializzata a 0 all'avvio (cstart), i valori memorizzati nella cache NON verranno utilizzati.

const volatile int temp; è una variabile memorizzata in FLASH (read-ony), inizializzata a 0 al momento del compilatore, i valori memorizzati nella cache NON verranno utilizzati

Ecco la parte utile:

Oggigiorno la maggior parte dei processori Embedded ha la capacità di apportare modifiche alla propria memoria non volatile di sola lettura per mezzo di uno speciale modulo funzione, nel qual caso const int temppuò essere modificato in fase di esecuzione, anche se non direttamente. Detto in altro modo, una funzione può modificare il valore all'indirizzo in cui tempè memorizzato.

Un esempio pratico potrebbe essere quello di utilizzare tempper il numero di serie del dispositivo. La prima volta che il processore integrato viene eseguito, tempsarà uguale a 0 (o il valore dichiarato) e una funzione può utilizzare questo fatto per eseguire un test durante la produzione e, in caso di successo, chiedere di essere assegnato un numero di serie e modificare il valore di tempmediante di una funzione speciale. Alcuni processori hanno un intervallo di indirizzi speciale con memoria OTP (programmabile una tantum) solo per questo.

Ma ecco la differenza:

Se const int tempè un ID modificabile invece di un numero di serie programmabile una tantum e NON è dichiarato volatile, un valore memorizzato nella cache potrebbe essere utilizzato fino al successivo avvio, il che significa che il nuovo ID potrebbe non essere valido fino al prossimo riavvio, o peggio ancora, alcune funzioni potrebbe utilizzare il nuovo valore mentre altri potrebbero utilizzare un vecchio valore memorizzato nella cache fino al riavvio. Se viene const int tempdichiarato IS voltaile, la modifica dell'ID avrà effetto immediato.


Wow, questa risposta è lunga

5

Puoi usare conste volatileinsieme. Ad esempio, se 0x30si presume che sia il valore di una porta che viene modificato solo da condizioni esterne, la seguente dichiarazione impedirebbe ogni possibilità di effetti collaterali accidentali:



2

In termini semplici, il valore nella variabile "const volatile" non può essere modificato a livello di programmazione ma può essere modificato dall'hardware. Volatile qui serve a prevenire qualsiasi ottimizzazione del compilatore.


1

Usiamo la parola chiave 'const' per una variabile quando non vogliamo che il programma la cambi. Mentre quando dichiariamo una variabile 'const volatile' diciamo al programma di non cambiarla e al compilatore che questa variabile può essere modificata in modo imprevisto da input provenienti dal mondo esterno.

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.