Writing to a variable that is originally const
is undefined behaviour, so all your example writes to *p
are undefined.
Removing volatile
in itself is not undefined in and of itself.
However, if we have something like const volatile int *p = (const volatile int*)0x12340000; /* Address of hw register */
, then removing volatile
may cause the hardware to update the register value, but your program doesn't pick it up. (E.g. if we "busy wait" with while(*p & 0x01) ;
, the compiler should reload the value pointed to by p
every time, but while((*(const int *)p) & 1) ;
, the compiler is entirely free to read the value ones, and re-use the initial value to loop forever if bit 0 is set).
You could of course have extern volatie int x;
and then use const volatile int *p = &x;
in some code, and x
gets updated by some other piece of code outside of your current translation unit (e.g. another thread) - in which case removing either const
or volatile
is valid, but as above, you may "miss" updated values because the compiler doesn't expect the global value to get updated outside of your module unless you call functions. [Edit, no, taking away volatile
by casting the value is also forbidden in the standard - it is however valid to add const
or volatile
to something, and then remove it again if it the original object referred to did not have it].
Edti2: volatile
is needed to tell the compiler that "the value may change at any time, even if you think nothing should have changed it". This happens, in general, in two situations:
- Hardware registers that are updated outside of the software altogether - such as status registers for a serial port, a timer-counter register, or interrupt status of the interrupt controller, to name a few case - there are thousands of other variations, but it's all the same idea: The hardware changes the value, without direct relation to the software that is accessing such registers.
- Variabled updated by another thread within the process (or in case of shared memory, by another process) - again, the compiler won't be able to "see" such changes. Often, one can write code that appear to function correctly by calling a function inside wait-loops and such, and the compiler will the reload values of non-local variables anyway, but some time later the compiler decides to inline that function call, and then realizes that the code is not updating that value, so doesn't reload the value -> bug when you inspect the "updated" value and find the same old value that the compiler had already loaded earlier.
Note also that volatile
is NOT a guarantee for any kind of thread/process correctness - it will just guarantee that the compiler doesn't skip over reads or writes to that variable. It is still up to the programmer to ensure that for example multiple values that are dependent on ordering are indeed updated in the correct order, and on systems where caches are not coherent between processing units, that the caches are made coherent via the software [for example a CPU and a GPU may not use coherent memory updates, so a write by the CPU does not reach the GPU until the cache has been flushed on the CPU - no amount of applying volatile
to the code will fix this]