2015-07-07 19 views
5

Avviso [...]: un comportamento indefinito: l'ordine degli accessi volatili non è definito in questa informativa x.cpp xxxQual è la logica di questo comportamento indefinito?

Perché questa linea è un comportamento indefinito?

case 2: 
    Vdda = 3.3 * (*VREFINT_CAL)/ADC_DR->DATA; 

Se le dichiarazioni/inizializzazioni sono:

volatile short const *VREFINT_CAL = (short *) 0x1FFFF7BA; 

e

volatile STRUCT_ADC_DR *ADC_DR = (STRUCT_ADC_DR*) 0x40012440; 

definito da:

typedef struct 
{ 
    unsigned DATA   : 16; 
    unsigned    : 16; 
} STRUCT_ADC_DR; 

E 'perché il compilatore non è sicuro circa la elementi volatili potrebbero agire diversamente nell'ordine in cui sono accessibili? (Che cos'è il caso)

Ma non si dovrebbe garantire che il calcolo venga eseguito da sinistra a destra poiché gli operatori hanno la stessa priorità?

+0

Sei sicuro di sapere che cosa 'volatile' fa? E perché ci sono indirizzi hardcoded nel tuo codice? – deviantfan

+1

Penso che questo debba essere riformulato come "perché lo standard indica esplicitamente questo come comportamento non definito/qual è la logica per ...", altrimenti otterrete "lo standard dice così" da molte persone. – OMGtechy

+6

L'ordine di valutazione degli operandi non è specificato. – molbdnilo

risposta

10

volatile implica che il compilatore sta leggendo qualcosa che non è un indirizzo di memoria ordinario, come una porta I/O. Per due di queste letture, è molto probabile che tu voglia che quelle letture avvengano in un certo ordine.

In entrambi C e C++, l'ordine di valutazione degli operandi non è definito. Se aiuta, pensare alla divisione come una chiamata di funzione:

Vdda = 3.3 * divide(*VREFINT_CAL, ADC_DR->DATA); 

Il punto è ora, che per volatile, dove è probabile che l'ordine è importante, non si potrebbe desiderare di lasciare questa decisione al compilatore . Quindi avvisa a riguardo.

Per eliminare l'avviso, è sufficiente rendere l'ordine esplicito introducendo ulteriori punti di sequenza sul codice. Per esempio:

short const x = *VREFINT_CAL; 
unsigned const y = ADC_DR->DATA; 
Vdda = 3.3 * x/y; 
+2

Hai ragione. Potrei avere grossi problemi quando si accede a DATA prima di VREFINT_CAL perché provoca il reset del valore. – dhein

+0

@Zaibis Felice di sentire che l'avviso in realtà ti aiuta a cogliere un bug in questo caso. – ComicSansMS

+0

@Zaibis In effetti, il link Alf riportato ti dice esattamente questo, quando rispondi alla domanda "È un problema?": Dipende dai tuoi dati e dal modo in cui le tue applicazioni lo gestiscono. Il compilatore sta dicendo che * può * causare problemi poiché il suo compito è lontano da qualsiasi altra cosa. – edmz

4

Per capire questo è necessario conoscere la differenza tra ordine di valutazione e la precedenza.

Prendete la vostra espressione, ad esempio:

Vdda = 3.3 * (*VREFINT_CAL)/ADC_DR->DATA; 

precedenza (e tra parentesi) determina come l'albero di sintassi astratta (AST) è costruito. Il risultato sarebbe qualcosa di simile:

= 
    Vdda 
    * 
    3.3 
    /
     * 
     VREFINT_CAL 
     -> 
     ADC_DR 
     DATA 

L'ordine di valutazione è determinato dall'esistenza di punti di sequenza. E il tuo codice ha un solo punto di sequenza, alla fine dell'espressione (;).

Quindi l'ordine di valutazione di qualsiasi sottoespressione non è specificato. Cioè, il compilatore può fare qualsiasi calcolo intermedio e accesso alla memoria in qualsiasi ordine ritenga opportuno. Ad alcune persone piace pensare che le sottoespressioni siano valutate da sinistra a destra, ma non è così che funziona la lingua.

Normalmente non farà alcuna differenza, ma due dei tuoi sottoespressioni sono volatile (*VREFINT_CAL e ADC_DR->DATA) in modo che le questioni di ordine. Forse non ha importanza per te, ma è certamente importante per il compilatore.

per risolvere il problema utilizzare alcuni temporanea, solo per aggiungere un punto sequenza intermedia:

short a = *VREFINT_CAL; 
unsigned b = ADC_DR->DATA; 
Vdda = 3.3 * a/b; 
+0

@Zaibis: Beh, sì.Ma hai ancora bisogno di una variabile locale: "breve a; a = * VREFINT_CAL, b = ADC_DR-> DATA, Vdda = 3.3 * a/...; '. Se provi a fare: 'Vdda = 3.3 * (0, * VREFINT_CAL)/...;' questo non funzionerà. – rodrigo

Problemi correlati