The proper use of C’s volatile keyword is poorly understood by many programmers. This is not surprising, as most C texts dismiss volatile in a sentence or two. This article will teach you the proper way to use volatile.
Have you ever faced this issue, when you are testing your code independently or without any compiler optimization, it works perfectly fine but as soon as you integrate it with system code or perform compiler optimization, the things start to crash and no longer provides the same output?
Have you experienced any of the following in your C or C++ embedded code?
- Code that works fine–until you enable compiler optimizations
- Code that works fine–until interrupts are enabled
- Flaky hardware drivers
- RTOS tasks that work fine in isolation–until some other task is spawned
If you answered yes to any of the above, it’s likely that you didn’t use the C keyword volatile. You aren’t alone: the use of volatile is poorly understood by too many programmers. It’s not so straight forward to have a sample working C program which can easily showcase the exact effect of “volatile” keyword. You probably won’t be able to use a variable which is qualified as “volatile“ unless you’re doing some low-level hardware programming in C.
What is a Volatile Variable?
Many a times, when you compile a C/C++ code, the compiler optimizes the code to reduce unnecessary processing. Take the following code for example:
In the above code, we are receiving data in a variable called “
receivedData.” Inside the
main() function, we are forwarding this data if the data is greater than 20. All looks fine with this code. However, if the compiler optimization is switched on, the compiler will assume that the value of “
receivedData” is not changing. Hence, it creates a copy of the variable and uses the copy for execution. Now, whenever we receive new data, our
main() function is not seeing the updated value because it is using a copy. This can be a serious problem.
The variable “
receivedData” is volatile as it can change at any time unexpectedly. So, it is always a good idea to tell it to the compiler that it is a volatile variable and to not optimize it.
A volatile variable is one that can change unexpectedly, it means the compiler cannot make any assumption about its value.
Volatile keyword is intended to prevent the compiler to perform any optimization on that object, that can change in ways which cannot be determined by compiler.
The object can be a memory, register, SFR.
What is a Volatile Keyword in C?
C’s volatile keyword is a qualifier that is applied to a variable when it is declared. It tells the compiler that the value of the variable may change at any time–without any action being taken by the code the compiler finds nearby. The implications of this can be quite serious, and sometimes software experts testify in regard to product failures. But before we examine the implications, let’s take a look at the syntax.
Syntax of C’s volatile Keyword
To declare a variable volatile, include the keyword volatile before or after the data type in the variable definition. For instance both of these declarations will declare an unsigned 16-bit integer variable to be a volatile integer:
Volatile Integer in C/C++
volatile uint16_t x;
uint16_t volatile y;
Pointer to Volatile Integer in C/C++
Now, pointers to volatile variables are very common, especially with memory-mapped I/O registers. Both of these declarations declare p_reg to be a pointer to a volatile unsigned 8-bit integer:
volatile uint8_t * p_reg;
uint8_t volatile * p_reg;
In case you do know to use pointers, or are not very confident, do not worry. Pointers in C/C++ are very easy. Click on the link to read.
Wrong use of Pointer to Volatile Integer in C/C++
//volatile integer variable volatile int num; //integer pointer int* ptr = #
Correct use of Pointer to Volatile Integer in C/C++
//volatile integer variable volatile int num; //integer pointer volatile int* ptr = #
And just for completeness, if you really must have a volatile pointer to a volatile variable, you’d write:
uint16_t volatile * volatile p_y;
Volatile Structure or Union in C/C++
Finally, if you apply volatile to a struct or union, the entire contents of the struct or union are volatile. If you don’t want this behavior, you can apply the volatile qualifier to the individual members of the struct or union.
Proper Use of C’s volatile Keyword
A variable should be declared volatile whenever its value could change unexpectedly. In practice, only three types of variables could change:
1. Memory-mapped peripheral registers
2. Global variables modified by an interrupt service routine
3. Global variables accessed by multiple tasks within a multi-threaded application
Consequences of over usage of volatile
Volatile variable forces compiler not to keep a copy and always get the fresh value from memory and register which takes more clock cycles. For real-time application, you should always perform timing analysis on a volatile variable to check it fulfills the timing requirement.
Vivek is a Senior Embedded Engineer at Robert Bosch. He has been working on Embedded Systems for the past 10 years. He loves to share his knowledge and train those who are interested. Nerdyelectronics.com was started out of this interest.