Questa è una domanda su ISO C, che contiene questa frase:
If an attempt is made to refer to an object defined with a volatile-qualified type through use of an lvalue with non-volatile-qualified type, the behavior is undefined.
In ISO9899: 1999 (C99) questo appare in 6.7.3 Qualificatori di tipi .
In primo luogo, se abbiamo completamente rimosso questa frase dal testo, il comportamento sarebbe ancora indefinito? Vale a dire, questa ripresentazione di una mancanza esistente di un requisito, o sta rimuovendo esplicitamente un requisito che altrimenti potrebbe essere dedotto da altre parti del testo? (Immagina che sia stata aggiunta una frase che dice "ogni volta che due valori di tipo int vengono sommati insieme la cui somma aritmetica è quarantadue, il comportamento non è definito". Senza tale frase, il requisito per tale aggiunta di produrre un valore può (ed è) dedotto).
In secondo luogo, quali comportamenti utili consente a un'implementazione di fornire? Vale a dire, può un'implementazione fare qualcosa di utile che interrompe i programmi che accedono a qualcosa di volatile con un non- volatile lvalue e che quindi dipende dalla frase sopra? Esistono implementazioni che lo fanno, qualunque esso sia?
Ad esempio, è interessante e degno di nota il fatto che i programmi C possano accedere a const -qualificati con% nonconst lvalue, ma non memorizzarli. Rendere il comportamento del negozio indefinito è tangibilmente vantaggioso: le implementazioni possono posizionare le costanti nella memoria di sola lettura e in alcuni casi possono propagare costanti attraverso un'immagine del programma al momento della traduzione come se fossero costanti manifeste. Tuttavia, per funzionare è sufficiente l'accesso non% di% co_de. Non è necessario che gli accessi non const a const oggetti da lavorare siano presumibilmente una permissività che non porta vantaggi. Tuttavia, nel caso di const , è così rigoroso: non è richiesto nessun non- volatile -qualificato per funzionare. Qual è il vantaggio?
Può un oggetto che è definito come volatile dal programma C stesso essere dotato di proprietà utili che si interrompono se si verificano accessi di qualunque tipo a quell'oggetto attraverso un non- volatile lvalue?
(Sotto "utile", vorrei in particolare escludere la diagnosi. Terminare il programma dopo aver rilevato un tale accesso, senza un messaggio, o con un messaggio come "volatile acceduto come non volatile" non conta come utile; serve solo a far rispettare la mancanza di requisiti.)
(Inoltre, non sono interessato ai registri mappati in memoria e ad oggetti rigorosamente definiti dal programma in archivi statici, dinamici o automatici. L'uso di registri hardware è intrinsecamente non proporzionale.)
Tutto quello che posso pensare è che un% nonvolatile di accesso a un oggetto volatile potrebbe recuperare un valore non aggiornato, piuttosto che il valore che è stato archiviato l'ultima volta
(correttamente, tramite volatile lvalue). Questo è un vantaggio economico nel modo seguente: se una scrittura avviene attraverso, ad esempio, un volatile lvalue, il compilatore non deve sospettare che questo abbia alcun effetto su qualsiasi valore volatile int lvalue. Questo porta a una migliore generazione del codice in funzioni che funzionano con miscele int e non volatile oggetti dello stesso tipo:
volatile int global;
void foo(int *p)
{
int x = *p, y;
global++;
y = *p;
}
Qui, il compilatore non deve considerare che volatile potrebbe essere un alias per *p , perché quell'utilizzo non è richiesto per funzionare secondo ISO C. Quindi può liberamente assumere che il valore di global non cambia tra i due riferimenti. Sia *p che x ricevono lo stesso valore, derivato da un singolo accesso a y .
Se l'aliasing era permesso, il compilatore avrebbe dovuto generare codice per ricaricare *p sul secondo accesso, in modo che rilevasse il valore più recente memorizzato in *p .
(Se rimuoviamo global dal frammento di programma sopra, allora questo è in realtà il caso, deve essere almeno sospettato, se non confermato. che volatile potrebbe essere un alias per *p e quindi global deve essere ricontrollato oppure deve essere generato codice che confronta il valore di runtime di *p con l'indirizzo di p e prende due percorsi diversi.)
Tuttavia, non introduciamo global nei programmi per ottenere questo tipo di oscuro beneficio di ottimizzazione; è usato per sconfiggere l'ottimizzazione. La parola chiave volatile può invece essere utilizzata per consentire all'implementazione di ragionare su lvalue non sottoposti ad aliasing. Sembra che quanto sopra non possa essere la logica.