94

volatile is to tell the compiler not to optimize the reference, so that every read/write does not use the value stored in register but does a real memory access. I can understand it is useful for some ordinary variable, but don't understand how volatile affects a pointer.

volatile int *p = some_addr;
int a = *p; // CPU always has to load the address, then does a memory access anyway, right?

What is the difference if it has been declared as int *p = some_addr?

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
Infinite
  • 3,198
  • 4
  • 27
  • 36

3 Answers3

169

A pointer of the form

volatile int* p;

is a pointer to an int that the compiler will treat as volatile. This means that the compiler will assume that it is possible for the variable that p is pointing at to have changed even if there is nothing in the source code to suggest that this might occur. For example, if I set p to point to a regular integer, then every time I read or write *p , the compiler is aware that the value may have changed unexpectedly.

There is one more use case for a volatile int*: If you declare an int as volatile, then you should not point at it with a regular int*. For example, this is a bad idea:

volatile int myVolatileInt;
int* ptr = &myVolatileInt; // Bad idea!

The reason for this is that the C compiler no longer remembers that the variable pointed at by ptr is volatile, so it might cache the value of *ptr in a register incorrectly. In fact, in C++, the above code is an error. Instead, you should write:

volatile int myVolatileInt;
volatile int* ptr = &myVolatileInt; // Much better!

Now, the compiler remembers that ptr points at a volatile int, so it won't (or shouldn't!) try to optimize accesses through *ptr.

One last detail - the pointer you discussed is a pointer to a volatile int. You can also do this:

int* volatile ptr;

This says that the pointer itself is volatile, which means that the compiler shouldn't try to cache the pointer in memory or try to optimize the pointer value because the pointer itself might get reassigned by something else (hardware, etc.) You can combine these together if you'd like to get this beast:

volatile int* volatile ptr;

This says that both the pointer and the pointee could get changed unexpectedly.The compiler can't optimize the pointer itself, and it can't optimize what's being pointed at.

starball
  • 20,030
  • 7
  • 43
  • 238
templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • 1
    I think it's an error in C as well, but C compilers are less prone to complain about type mismatches. – Chris Lutz Mar 29 '12 at 23:53
  • Thanks. So it has no difference whether there is "volatile" for my example, right? But if there is another statemenet "int b = *p" following, it does make a difference, right? Specifically, "b" may be initialized using a register storeing "*p" instead of doing a real memory reference. – Infinite Mar 29 '12 at 23:55
  • @SetTimer- The C spec is sufficiently general that ideas like "caches," "registers," and "memory references" don't exist. The compiler will *probably* not hold the variable in a register, but it could in theory be smart enough to notice that the `int` being pointed at is not marked `volatile` and thus would compile the code identically with and without `volatile`. – templatetypedef Mar 29 '12 at 23:57
  • @templatetypedef: I doubt that's valid. Even if the pointed-to object was not declared volatile, one might want to access it as a volatile object overlaid with the non-volatile object, and as far as I can tell C's type compatibility rules allow such usage. – R.. GitHub STOP HELPING ICE Mar 30 '12 at 00:01
  • @R..- Sorry, to clarify - at a language level, you can definitely assign the pointer. However, the compiler might be smart enough to realize that doing so has no actual impact on the program semantics, and could just treat the pointer as non-`volatile`. It would have to be a very smart compiler to do this, though. Or am I incorrect about this? – templatetypedef Mar 30 '12 at 00:04
  • @templatetypedef I am still confused. Say you have the code "int *p = &x; a = *p; do_something_else; b = *p;" I cannot imagine "b" would be assigned using a value that has been read for "a = *p", because that would be so wrong if the value of x has been changed somehow. My point is that even there is no volatile, I should expect "b = *P" will lead to a real read using the address of x rather than an old value stored in a register. – Infinite Mar 30 '12 at 00:13
  • 1
    @SetTimer- That really depends on what `do_something_else` is. If the compiler could be completely convinced that `do_something_else` never changed the value of `x`, then it could definitely read the value of `*p` out of a register if it wanted. I doubt that for any reasonable code and most compilers that this would actually happen, but in theory it would be possible. Does that make sense? – templatetypedef Mar 30 '12 at 00:16
  • The C standard does not say that "the compiler will assume that it is possible for the variable that p is pointing at to have changed even if there is nothing in the source code to suggest that this might occur". It says that accesses to volatile *objects* can't be optimized away. If the compiler knows a pointer to volatile points to a non-volatile object then it can optimize away access. See my answer to [Requirements for behavior of pointer-to-volatile pointing to non-volatile object](https://stackoverflow.com/a/28655297/3404097). – philipxy Feb 22 '15 at 13:10
  • @philipxy: You are wrong. There is a defect report which clarifies how `volatile` is to be treated and that the wording in the standard is missleading. Luckily according to the report, most - if not all - implementations do it correctly and as intended. – too honest for this site Aug 10 '16 at 21:08
  • @olaf That's great. I wouldn't exactly say I was wrong, since I correctly described what the standard says, as you confirm. Of course, what a program is supposed to do is per the standard as amended by a defect report of the right status. As I say in the linked answer, the standard did not seem to reflect the intent. Do you happen to know which report and its status? – philipxy Aug 12 '16 at 02:06
  • @philipxy: Well, if you read the report carefully, you might notice it states the wording in the standard is not what was meant, that the C++ standard is more what was **intended** by the commitee and that all major implementations implement what was intended, not what is written. So, I very well think you are wrong in terms of intention and practice (which is more relevant here than the theory. – too honest for this site Aug 12 '16 at 02:12
  • 1
    @olaf Defect Report Summary for C11 Version 1.10 Date: April 2016 [DR 476 volatile semantics for lvalues](http://www.open-std.org/jtc1/sc22/wg14/www/docs/summary.htm#dr_476) 04/2016 Open – philipxy Feb 19 '17 at 02:07
  • @philipxy: What the Standard should say is that the appropriate semantics for `volatile` will vary depending upon the target platform and intended application field. On many platforms, having a `volatile` read behave with acquire semantics and a volatile `write` behave with release semantics would be appropriate. On some platforms where reads can trigger hardware actions, they should have release as well as acquire semantics; likewise on some platforms where a write can trigger a stall until an I/O operation completes, they should have acquire as well as release semantics. – supercat Jul 17 '18 at 23:49
  • @philipxy: On a platform that have no means of raising signals or doing anything else unusual, `volatile` need not do anything for objects other than automatic objects in functions that use `setjmp`, and counting as a "side effect" for purposes of preventing loop elision. The Standard should give implementors the authority to decide what's appropriate, but make clear that quality implementations will generally do more than the minimum required by the Standard [a note that should be applied in many other places as well]. – supercat Jul 17 '18 at 23:53
  • About the "Bad idea!" example, if I understand the C11 standard correctly, §6.5.16.1 under constraints states that discarding qualifiers is not allowed in this case. Both recent clang and gcc warn about this, but unfortunately allow it (with default options). – Garogolun Nov 12 '18 at 14:09
  • In *"is a pointer to an int that the compiler will treat ..."* I needed a moment to clearly understand that *"that"* refers to the int, not to the pointer. Anyway, great explanation! – Droidum May 15 '19 at 14:01
  • I have an other thought/question concerning the "beast" as you named it. If I declare a volatile **pointer** does it make a difference then if the **value** pointed to is volatile or not? In my opinion the value pointed to must not be cached in this case even if it is not explicitely marked volatile. Because if the path to the value can change at any time, the value can change at any time too. Yes that's quite theoretical but nevertheless interestint :-) – Droidum May 17 '19 at 08:47
10

This code volatile int *p = some_addr declares a pointer to a volatile int. The pointer itself is not volatile.

In the unlikely event that you needed the pointer to be volatile as well as the int, you would need to use:

volatile int * volatile p;

I can't think of a situation where you would need to use that.

markgz
  • 6,054
  • 1
  • 19
  • 41
  • 6
    Example: I'm using 'volatile uint8_t* volatile pData' in ISR code that modifies the pointer and the data it points to. The pointer is set by the main code, and both pointer and data are read later. – Christoph Feb 24 '13 at 00:24
3

On the usefulness of volatile: This is needed, if you need to check memory, which is modified by hardware like a serial interface controller. It has its application in the world of embedded systems, where you work very close to the hardware without any OS in-between.