23

Consider the following code:

int square(volatile int *p)
{
    return *p * *p;
}

Now, the volatile keyword indicates that the value in a memory location can be altered in ways unknown to the compiler or have other unknown side effects (e.g. modification via a signal interrupt, hardware register, or memory mapped I/O) even though nothing in the program code modifies the contents.

So what exactly happens when we declare a pointer as volatile?

Will the above mentioned code always work, or is it any different from this:

int square(volatile int *p)
{
    int a = *p;
    int b = *p
    return a*b;
}

Can we end up multiplying different numbers, as pointers are volatile?

Or is there better way to do so?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
vishal
  • 2,258
  • 1
  • 18
  • 27
  • 14
    This is volatile pointer: `int * volatile p`, this is a pointer point to a volatile int: `volatile int *p` – Zang MingJie Oct 22 '15 at 12:23
  • 2
    related/dupe [Why is a point-to-volatile pointer, like “volatile int * p”, useful?](http://stackoverflow.com/questions/9935190/why-is-a-point-to-volatile-pointer-like-volatile-int-p-useful) – NathanOliver Oct 22 '15 at 12:29
  • Ok i understood how that works, but my question is that, will both function mentioned in Question produce same result? or os there any better way to use declare them – vishal Oct 22 '15 at 12:33
  • If `p` points to a hardware register or some memory mapped device, why would you want to multiply two independent reads from that? What is the use case? – Bo Persson Oct 22 '15 at 12:33
  • 1
    @vishal - willy's code will "work" in that you get a product. However, if `*p` is really connected to some external hardware, it might get a *different* result. Or the hardware might react differently to one or two accesses - like firing one or two missiles. – Bo Persson Oct 22 '15 at 13:40
  • Thanks for clearing that @BoPersson. – vishal Oct 22 '15 at 13:41

7 Answers7

14

Can a pointer be volatile?

Absolutely; any type, excluding function and references, may be volatile-qualified.

Note that a volatile pointer is declared T *volatile, not volatile T*, which instead declares a pointer-to-volatile.

A volatile pointer means that the pointer value, that is its address and not the value pointed to by, may have side-effects that are not visible to the compiler when it's accessed; therefore, optimizations deriving from the "as-if rule" may not be taken into account for those accesses.


int square(volatile int *p) { return *p * *p; }

The compiler cannot assume that reading *p fetches the same value, so caching its value in a variable is not allowed. As you say, the result may vary and not be the square of *p.

Concrete example: let's say you have two arrays of ints

int a1 [] = { 1, 2, 3, 4, 5 };
int a2 [] = { 5453, -231, -454123, 7565, -11111 };

and a pointer to one of them

int * /*volatile*/ p = a1;

with some operation on the pointed elements

for (int i = 0; i < sizeof(a1)/sizeof(a1[0]); ++i) 
       *(p + i) *= 2;

here p has to be read each iteration if you make it volatile because, perhaps, it may actually point to a2 due to external events.

edmz
  • 8,220
  • 2
  • 26
  • 45
  • 1
    Note cppreference has a good [as-if rule description](http://en.cppreference.com/w/cpp/language/as_if). – Shafik Yaghmour Oct 22 '15 at 13:17
  • 1
    Question for clarification: in your example (`square`), the value of the pointer (that is, the memory address that `p` represents, not the int-value that `*p` will give you) cannot change as far as I understand it: `p` is a local value passed-by-value to the function `square`. Under what conditions could the value of `p` (the memory address) possibly change? If you want a changeable pointer (aka *handle*), then it would be `square(**p)`. So what's the point of a "volatile" pointer? A pointer-to-volatile makes perfect sense to me... just not a "volatile pointer". – Christopher Schultz Oct 22 '15 at 20:54
  • @ChristopherSchultz It depends on the specific case: `p` could be global, or local and its address couldn't change as it's copied. However, consider that it could change from events that the compiler can't really see like some assembly code that modifies that particular address where the pointer is stored. But in general, `volatile` pointers are rarer to find. – edmz Oct 22 '15 at 22:04
  • @black The "global pointer" use-case certainly does make sense. I suppose the contrived example was confusing me: in the `square` function, a volatile pointer argument makes no sense at all, but other use-cases do make volatile pointers useful and, in some cases, required. Thanks for the clarification. – Christopher Schultz Oct 22 '15 at 22:16
12

Yes, you can of course have a volatile pointer.

Volatile means none more and none less than that every access on the volatile object (of whatever type) is treated as a visible side-effect, and is therefore exempted from optimization (in particular, this means that accesses may not be reordered or collapsed or optimized out alltogether). That's true for reading or writing a value, for calling member functions, and of course for dereferencing, too.

Note that when the previous paragraph says "reordering", a single thread of execution is assumed. Volatile is no substitute for atomic operations or mutexes/locks.

In more simple words, volatile generally translates to roughly "Don't optimize, just do exactly as I say".

In the context of a pointer, refer to the exemplary usage pattern given by Chris Lattner's well-known "What every programmer needs to know about Undefined Behavior" article (yes, that article is about C, not C++, but the same applies):

If you're using an LLVM-based compiler, you can dereference a "volatile" null pointer to get a crash if that's what you're looking for, since volatile loads and stores are generally not touched by the optimizer.

Damon
  • 67,688
  • 20
  • 135
  • 185
2

Yes. int * volatile.

In C++, keywords according to type/pointer/reference go after the token, like int * const is constant pointer to integer, int const * is pointer to constant integer, int const * const is constant pointer to constant integer e.t.c. You can write keyword before the type only if it's for the first token: const int x is equal to int const x.

Lapshin Dmitry
  • 1,084
  • 9
  • 28
2

The volatile keyword is a hint for the compiler (7.1.6.1/7):

Note: volatile is a hint to the implementation to avoid aggressive optimization involving the object because the value of the object might be changed by means undetectable by an implementation. Furthermore, for some implementations, volatile might indicate that special hardware instructions are required to access the object. See 1.9 for detailed semantics. In general, the semantics of volatile are intended to be the same in C ++ as they are in C. — end note ]

What does it mean? Well, take a look at this code:

bool condition = false;
while(!condition)
{
    ...
}

by default, the compiler will easilly optimize the condition out (it doesn't change, so there is no need to check it at every iteration). If you, however, declare the condition as volatile, the optimization will not be made.

So of course you can have a volatile pointer, and it is possible to write code that will crash because of it, but the fact that a variable is volative doesn't mean that it is necessarily going to be changed due to some external interference.

SingerOfTheFall
  • 29,228
  • 8
  • 68
  • 105
  • Are you sure? The compiler can easily see that `volatile bool condition = false` isn't memory mapped, isn't a hardware register and resides in a local scope where a signal handler cannot access it. So how can it change? – Bo Persson Oct 22 '15 at 12:44
  • 1
    `volatile` is not an "hint"; it has clear semantics: every access may be part of the observable behavior. It could be considered an hint what comes after that, namely the ineffectiveness of optimizations targeting the removal of accesses. – edmz Oct 22 '15 at 12:45
1

Yes, a pointer can be volatile if the variable that it points to can change unexpectedly even though how this might happen is not evident from the code.

An example is an object that can be modified by something that is external to the controlling thread and that the compiler should not optimize.

The most likely place to use the volatile specifier is in low-level code that deals directly with the hardware and where unexpected changes might occur.

dspfnder
  • 1,135
  • 1
  • 8
  • 13
0

You may be end up multiplying different numbers because it's volatile and could be changed unexpectedly. So, you can try something like this:

int square(volatile int *p)
{
int a = *p;
return a*a;
}
  • This example seems pointless to me, why have a parameter declared volatile if the very first thing you do in a function is assign it to a non-volatile variable, effectively making it not volatile for any further use in the function? – E. T. Jun 09 '19 at 17:51
0
    int square(volatile int *p)
    {
        int a = *p;
        int b = *p
        return a*b;
    }

Since it is possible for the value of *ptr to change unexpectedly, it is possible for a and b to be different. Consequently, this code could return a number that is not a square! The correct way to code this is:

    long square(volatile int *p)
    {
        int a;
        a = *p;
        return a * a;
    }
fn_cats
  • 24
  • 2