Let`s analyze this line.
volatile int * p;
declares a pointer to a volatile int
. A volatile int
is from the storage and semantics a normal int
. But volatile
instructs the compiler, that its value could change anytime or has other side effects.
On the right side of the assignment you have (int *) 0x0
. Here you tell the compiler, that it should assume a pointer to int
which points to the address 0x0
.
The full assignment volatile int * p = (int *) 0x0;
assigns p
the value 0x0
. So in total you told the compiler, that at address 0x0
is an integer value which has side effects. It can be access by *p
.
volatile
You seem to be unclear what volatile means. Take a look at this code:
int * ptr = (int *) 0x0BADC0DE;
*ptr = 0;
*ptr = 1;
An optimizing compiler would take a short look on this code and say: Setting *ptr
to 0
has no effect. So we will skip this line and will only assign 1
immediately to safe some execution time and shrink the binary at the same time.
So effectively the compiler would only compile the following code:
int * ptr = (int *) 0x0BADC0DE;
*ptr = 1;
Normally this is OK, but when we are talking about memory mapped IOs, things get different.
A memory mapped IO is some hardware that can be manipulated by accessing special RAM addresses. A very simple example would be an output -- a simple wire coming out of your processor.
So let's assume, that at the address 0x0BADC0DE
is a memory mapped output. And when we write 1
to it, this output is set to high and when we write 0
the output is set to low.
When the compiler skips the first assignment, the output is not changed. But we want to signalize another component something with a rising edge. In this case we want to get rid of the optimization. And one common way to do this, is to use the volatile
keyword. It instructs the compiler that it can't check every aspect of read or write accesses to this register.
volatile int * ptr = (int *) 0x0BADC0DE;
*ptr = 0;
*ptr = 1;
Now the compiler will not optimize the accesses to *ptr
and we are able to signalize a rising edge to an outside component.
Memory mapped IOs are important in programming embedded systems, operating systems and drivers. Another use case for the volatile
keyword would be shared variables in parallel computing (that in addition to the volatile
keyword would need some kind of mutex of semaphore to restrict simultaneous access to these variables).