2015-01-07 3 views
6

Considerate questo esempio di codice:Quando è possibile ottimizzare completamente una variabile volatile?

int main(void) 
{ 
    volatile int a; 
    static volatile int b; 

    volatile int c; 
    c = 20; 
    static volatile int d; 
    d = 30; 

    volatile int e = 40; 
    static volatile int f = 50; 

    return 0; 
} 

Senza volatile un compilatore potrebbe ottimizzare via tutte le variabili in quanto non sono mai leggere.

penso a e b può essere ottimizzato lontano dal momento che sono completamente inutilizzata, vedere unused volatile variable.

Penso che c e d non possano essere rimossi dal momento in cui sono stati scritti e le scritture in variabili volatili devono effettivamente verificarsi. e dovrebbe essere equivalente a c.

GCC non ottimizza via f, ma anche non emette alcuna istruzione per scrivere. 50 è impostato in una sezione dati. LLVM (clang) rimuove completamente f.

Queste affermazioni sono vere?

  1. Una variabile volatile può essere ottimizzata se non viene mai utilizzata.
  2. L'inizializzazione di una variabile statica o globale non viene considerata come accesso.
+0

possibile duplicato di [Perché è volatile necessario in c?] (Http://stackoverflow.com/questions/246127/why-is-volatile-needed-in-c) – Gopi

+0

Penso che questa domanda sia più specifica su come le variabili volatili possono essere ottimizzate. –

+0

era 'c = 30;' intendeva leggere 'd = 30;'? –

risposta

8

Le scritture su variabili volatili (anche quelle automatiche) valgono come comportamento osservabile.

C11 (N1570) 5.1.2.3/6:

dei minimi requisiti su conforme attuazione sono:

- Accessi agli oggetti volatili vengono valutate rigorosamente secondo le regole della macchina astratta .

- Al termine del programma, tutti i dati scritti in file devono essere identici al risultato che l'esecuzione di del programma in base alla semantica astratta avrebbe prodotto.

- La dinamica di ingresso e di uscita dei dispositivi interattivi si svolgono come specificato 7.21.3. L'intento di questi requisiti è che l'uscita buffer o linea tamponata appaiono più presto possibile, per assicurare che i messaggi spingendo effettivamente appaiono prima un programma in attesa di input.

Questo è il comportamento osservabile del programma.

La domanda è: non inizializzazione (e, f) conta come un "accesso"? Come sottolineato da Sander de Dycker, 6.7.3 dice:

Ciò che costituisce un accesso a un oggetto che è di tipo instabile qualificato è definito dall'implementazione.

che significa che è fino al compilatore o meno e e f può essere ottimizzato via - ma questo deve essere documentato!

+2

6.7.3 dice "Ciò che costituisce un accesso a un oggetto che ha tipo volatile è definito dall'implementazione.", Che indirizza l'ultimo paragrafo. –

4

In senso stretto qualsiasi variabile volatile a cui si accede (letto o scritto) non può essere ottimizzata secondo lo standard C. Lo standard dice che un accesso a un oggetto volatile può avere effetti collaterali sconosciuti e che l'accesso all'oggetto volatile deve seguire le regole della macchina astratta C (dove tutte le espressioni sono valutate come specificato dalla loro semantica).

Dalla possente standard (sottolineatura mia):

(C11, 6.7.3p7) "Un oggetto che ha tipo di volatili-qualificati possono essere modificati in modi sconosciuti al realizzazione o hai qualche sconosciuto effetti collaterali. Pertanto qualsiasi espressione che si riferisce a a tale oggetto deve essere valutata rigorosamente secondo le regole della macchina astratta, come descritto in 5.1.2.3. "

In seguito anche una semplice inizializzazione di una variabile deve essere considerata come un accesso. Ricordare che l'identificatore static provoca anche l'inizializzazione dell'oggetto (a 0) e quindi l'accesso.

Ora i compilatori si comportano in modo diverso con il qualificatore volatile e immagino che molti di essi ottimizzino solo la maggior parte degli oggetti volatili del programma di esempio, ad eccezione di quelli con l'assegnazione esplicita (=).

+1

Si noti che le dichiarazioni non sono espressioni –

+1

ma dice un po 'oltre: "Ciò che costituisce un accesso a un oggetto con tipo volatile qualificato è definito dall'implementazione." che spiega la differenza di comportamento menzionata tra gcc e llvm. –

+0

Se una variabile automatica volatile non ha il proprio indirizzo preso, ciò suggerirebbe che un compilatore potesse ottimizzare tutte le istruzioni che l'accedessero nelle stesse situazioni in cui potrebbe farlo per una variabile non volatile * ma * non potrebbe spostarsi un effetto collaterale che si verifica dopo tale accesso a un punto prima di esso e viceversa. – supercat