c++cpointersvolatilenon-volatile

Volatile Pointer to Non Volatile Data


Suppose I have the following declaration:

int* volatile x;

I believe that this defines a volatile pointer "normal" variable.

To me this could mean one of two things:

First Guess

The pointer can change, but the number will not change without notice. This means that some other thread (that the compiler doesn't know about) can change the pointer, but if the old pointer was pointing to a "12" then the new pointer (the new value of the pointer, because the thread changes it) would point to another "12".

To me this seems fairly useless, and I would assume that this is not what the real operation is.

Second Guess

The pointer can change, and thus if the pointer changes, the compiler must reload the value in the pointer before using it. But if it verifies that the pointer did not change (with an added check), it can then assume that the value it points to remained the same also.

So my question is this:

What does declaring a volatile pointer to non volatile data actually do?


Solution

  • int *volatile x; declares a volatile pointer to a non-volatile int.

    Whenever the pointer is accessed, the volatile qualifier guarantees that its value (the value of the pointer) is re-read from memory.

    Since the pointed-to int is non-volatile, the compiler is allowed to reuse a previously cached value at the address pointed to by the current value of the pointer. Technically this is allowed regardless of whether the pointer has changed or not, as long as there exists a cached value originally retrieved from the current address.


    [ EDIT ] To address @DavidSchwartz's comment, I should note that "re-read from memory" is a (not pedantically precise, but AFAIK commonly used) shorthand for "as if it were re-read from memory in the abstract machine".

    For example, C11 draft N1570 6.7.3/7 says:

    An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. Therefore any expression referring to such an object shall be evaluated strictly according to the rules of the abstract machine, as described in 5.1.2.3. Furthermore, at every sequence point the value last stored in the object shall agree with that prescribed by the abstract machine, except as modified by the unknown factors mentioned previously (134). What constitutes an access to an object that has volatile-qualified type is implementation-defined.

    The same draft has a footnote for 6.5.16/3 (assignment operators):

    The implementation is permitted to read the object to determine the value but is not required to, even when the object has volatile-qualified type

    So in the end volatile does not require a physical memory read, but the observable behavior of a compliant implementation must be as if one was made regardless.