Skip to content

Understand the Volatile Keyword in C/C++

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:

C-Volatile_effect

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 not know how to use pointers, or are not very confident, do not worry. Pointers in C/C++ are very easy. Click on the link to read.

Pointers in C/C++

 

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.

Leave a Reply

Your email address will not be published. Required fields are marked *