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.