Embedded

View Original

Explaining the C Keyword Volatile

The programming language you use is a conversation between you and the compiler. Understanding this helps with odd keywords. It isn’t about the language or the hardware, it is about what you want the compiler to tell the hardware.

Before we get to the keyword volatile, we need to talk about compiler optimization options. You know, those things that make your code run faster (or be smaller) even though all you do is change the compiler command line?

When compiler optimizations are off (-O0), the compiler tells the hardware exactly what you say. That’s what you think you want. But then you realize the compiler is kind of smart, at least with respect to optimization. It is better at assembly than you (maybe) or it has more time to make machine code that is fast. So you set it to optimize a little, then optimize a lot, because why not?

Except, now the compiler thinks you are stupid. Or if not stupid, then a bit sloppy. And lazy.

For example, you might write an interrupt service routine that sets a flag when the interrupt occurs. Until that happens, you opt to go into a low power state for a little while, waiting for the user to press a button or a sensor to finish sensing. Something like:

while ( INTERRUPT_HAPPENED != interruptFlag ) { 
    // keep returning to sleep until something happens 
    sleep() ; 
}

The compiler looks at all the surrounding code and says, “wow, that’s inefficient!” It knows that interruptFlag can never change in an empty while loop. Nothing happens there, the compiler might as well put in if statement:

if ( INTERRUPT_HAPPENED != interruptFlag ) {  
    // nothing is happening and it never will so sleep
sleep:
    sleep() ;
    goto sleep;
}

It is a smart compiler, it knows things about how variables changes and since interruptFlag can’t possibly change in this code, the compiler can eliminate the check in the future. Also, it is allowed to use goto statements. (You are not. Don’t pick up the compiler's bad habits.)

However, if you declare interruptFlag with a volatile keyword, you are letting the compiler know that interruptFlag is used somewhere else, outside the obvious path, and the compiler shouldn’t make any assumptions about it. Note that the type (char, int, float) doesn’t matter, the purpose of volatile is to say “no, this isn’t dumb and you don’t know everything.”

So use volatile for things that might change outside the scope of the current function, such as global variables you set in interrupts and use in normal code. Or a variable set in one thread of an operating system to signal another. Or on a memory mapped device register that changes because something happens in hardware.

Thus, the volatile keyword tells the compiler that you aren’t an idiot. Use it sparingly or the compiler will miss opportunities to clean up your code.

My beagle thinks I’m stupid for not rolling in dead things. Or not letting her eat random mushrooms that grow in the yard. Or playing with robots when I could be throwing the tennis ball for her. 

You may also enjoy Nine Ways To Break Your System Code Using Volatile and How To Use C's Volatile Keyword