Reputation: 21400
Does volatile write to volatile const introduce undefined behavior? What if I drop volatile when writing?
volatile const int x = 42;
const volatile int *p = &x;
*(volatile int *)p = 8; // Does this line introduce undefined behavior?
*(int *)p = 16; // And what about this one?
Upvotes: 3
Views: 293
Reputation: 37934
It is undefined behavior (for both statements) as you attempt to modify the "initial" const
object. From C11 (N1570) 6.7.3/p6 Type qualifiers (emphasis mine):
If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined.
For completeness it may be worth adding, that Standard says also that:
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.
Hence latter statement, that is:
*(int *)p = 16;
is undefined for second phrase as well (it's a "double UB").
I believe that rules are the same for C++, but don't own copy of C++14 to confirm.
Upvotes: 8
Reputation: 129374
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 [Edit, no, taking away 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.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:
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]
Upvotes: 5