Sure it does not hurt but then why not just make everything "volatile".
You could, but then the compiler could not optimize the code much. The code would work as intended, but be slower than necessary.
It makes no sense to do it as a precaution, just in case.
No, but a lot of "programmers" throw stuff at the wall, and see what sticks. The honest ones will tell you that "this is how I got it to (seem to) work, but I don't know how or why". I consider them similar to software engineers as alchemists are to chemists.
AIUI, if you read location 0x0800000 into some variable then that variable must be "volatile", but code which subsequently accesses that variable does not have to be.
I'd prefer putting it a bit different way (since I'm not sure if that sentence describes the situation correctly or not; my English fails me here).
You declare a variable (or an object like an array)
volatile, when you do not want the compiler to infer its value in any way, and want the compiler to access the actual storage (memory) of it whenever the variable or object is accessed.
If you look at ataradovs above example, you'll see the pattern of how to make a single access volatile: you construct a pointer to the volatile data, with the pointer pointing to the object or address you want, and then dereference the pointer. The value is stored in a non-volatile variable. To aid us human programmers, I like to explicitly declare such "locally cached values" as
const –– which is just a promise to the compiler that we only read the value, and will not try to modify it, making it easier for the compiler to optimize the code using the
const values. (GCC and Clang are pretty darned good at inferring
constness on their own, though, so in practice, it really is more a reminder to us humans that this value will stay constant in this scope.)
volatile is not the only way to tell the compiler that its assumptions about variables or objects are no longer valid. In GCC, on all architectures,
asm volatile ("" : : : "memory"); acts as a compiler memory barrier (generates no machine code itself!) that tells the compiler that any assumptions about memory contents across that statement are invalid. However, it does not affect local variables and objects, since these are on stack.
Another way is to call a function whose prototype is known but implementation unknown – for example, compiled in a separate unit (C source file) –, that takes a pointer to the non-
const memory range containing one or more variables. For a specific variable or object (including a dereferenced pointer), you can also use
asm volatile ("" : "+m" (object)); which tells the compiler that any assumptions about the value of
object become invalid at that point.
How would you totally avoid "volatile" in this scenario?
For example,
asm volatile ("" : "+m" (*(uint32_t *)0x0800000)); uint32_t variable = *(uint32_t *)0x0800000; asm volatile ("" : "+m" (*(uint32_t *)0x0800000));does the exact same thing.
In pure C, without inline assembly, there is no exactly equivalent alternate to
volatile whose behaviour the standard guarantees. In practice, bracketing the access with a call to a function, say
foo((uint32_t *)0x0800000); with the implementation of
foo() not visible to the compiler (but prototype e.g.
void foo(uint32_t *); , the compiler would have to load the 32-bit unsigned integer at that point in the code.