2012-11-02 14 views
6

Folks,Significato volatile per array e typecasts

considerare questo (abominevole) pezzo di codice:

volatile unsigned long a[1]; 
unsigned long T; 

void main(void) 
{  
    a[0] = 0x6675636b; /* first access of a */ 
    T = *a; 
    *(((char *)a) + 3) = 0x64; /* second access of a */ 
    T = *a; 
} 

... la domanda: è ((char *)a) volatile o non volatile?

Questo solleva una domanda più ampia: dovrebbe esserci una dipendenza tra i due accessi di a? Cioè, il buon senso umano dice che esiste, ma lo standard C99 dice che le cose volatili non sono alias delle cose non volatili - quindi se ((char *)a) non è volatile, allora i due accessi non sono alias, e non c'è una dipendenza.

Più correttamente, C99 6.7.3 (paragrafo 5) legge:

"Se viene fatto un tentativo per fare riferimento a un oggetto definito con un tipo volatili qualificato attraverso l'uso di un Ivalue con non volatile -qualificato il tipo, il comportamento non è definito. "

Così, quando abbiamo typecast a, si applica il qualificatore volatili?

+0

Penso che tu abbia risposto alla tua stessa domanda, non è definito. In realtà non penso che la volatilità abbia alcun effetto, è una sorta di suggerimento del compilatore che viene ignorato sulle piattaforme comuni. –

+1

@ AndrewTomazos-Fathomling "Non penso che la volatilità abbia alcun effetto, è una sorta di suggerimento del compilatore che viene ignorato sulle piattaforme comuni" Potresti pensare a 'register'. Il qualificatore di tipo "volatile" ha un significato molto significativo nel codice C del 2012, dal momento che le mode del momento (per C) sono l'ottimizzazione aggressiva e le applicazioni incorporate, entrambe possono coesistere solo con suggerimenti del programmatore come "volatile". –

+1

@ AndrewTomazos-Fathomling, no 'volatile' non è solo un suggerimento, è un ordine per caricare il valore dalla memoria a * ogni * accesso. –

risposta

0

come hai detto tu, è "indefinito". Il che significa che i demoni possono uscire dal tuo naso. Si prega di attenersi ai comportamenti "definiti" il più possibile. Un identificatore volatile chiederà al compilatore di non ottimizzare il valore, poiché è un valore "importante" e critico che potrebbe causare problemi se modificato a causa di diversi meccanismi di ottimizzazione. Ma questo è tutto can do.

1

In caso di dubbio, eseguire del codice :) Ho incitato alcuni simili (un po 'meno abominevole) codice di prova (++ applicazione win32 C in MSVS 2K10)

int _tmain(int argc, _TCHAR* argv[]) { 
    int a = 0; 
    volatile int b = 0; 

    a = 1; //breakpoint 1 
    b = 2; //breakpoint 2 
    *(int *) &b = 0; //breakpoint 3 
    *(volatile int *) &b = 0; //breakpoint 4 

    return 0; 
} 

Quando compilato per il rilascio, mi ha permesso di breakpoint a 2 e 4, ma non 1 e 3.

La mia conclusione è che il typecast determina il comportamento e 1 e 3 sono stati ottimizzati. Intuition supporta questo, altrimenti il ​​compilatore dovrebbe mantenere un certo tipo di elenco di tutte le posizioni di memoria elencate come volatili e controllare ogni accesso (duro, brutto), piuttosto che associarlo semplicemente con il tipo di identificatore (più semplice e intuitivo) .

Ho anche il sospetto che sia specifico del compilatore (ed eventualmente specifico del flag anche all'interno di un compilatore) e che verrebbe testato su qualsiasi piattaforma prima di dipendere da questo comportamento.

realtà graffio che, vorrei semplicemente cercare di non dipendere da questo comportamento :)

Inoltre, so che stavi chiedendo specificamente sugli array, ma dubito che fa la differenza. Puoi facilmente creare un codice di prova simile per gli array.