cpp-variables-volatile

Volatile Variables in C++

  • 3 min

In C++, the volatile keyword is a type modifier that tells the compiler that the value of a variable can change at any time (and without the compiler being able to foresee it).

When optimizing code, the compiler assumes that the value of a variable does not change outside of the instructions that directly affect it in the source code (which are the ones the compiler controls).

This can lead it to perform certain optimizations, such as caching the variable’s value or eliminating unnecessary accesses.

By declaring a variable with the volatile modifier, we are telling the compiler that it should not perform certain optimizations when working with that variable.

This is useful when the variable’s value can change unexpectedly. For example due to:

  • Hardware Access: When interacting directly with hardware registers, the value of these registers can change at any time due to external events.
  • Multithreading: In multithreaded applications, a variable shared between threads can be modified by one of the threads at any moment.
  • Interrupts: Interrupts can also alter a variable’s value unexpectedly.

How to Use volatile

To declare a variable as volatile, simply add the volatile modifier in the variable declaration:

volatile int myVar;
Copied!

In this declaration, myVar is a variable that can be modified at any time by factors external to its use in the code.

Example of Use in Hardware Access

A typical use case for volatile is when interacting with hardware registers in embedded systems programming. Let’s see it with a simple example:

Suppose we have a machine with a while() loop to wait until someone presses a button.

#include <iostream>

// Variable simulating a hardware register (modified by external hardware)
volatile bool buttonPressed = false;

void checkButton() {
    while (!buttonPressed) {
        // Active wait: the program stays here until the button is pressed
    }
    std::cout << "Button pressed!" << std::endl;
}

int main() {
    std::cout << "Waiting for the button to be pressed..." << std::endl;

    // Simulate that the hardware presses the button after some time
    buttonPressed = true;

    checkButton();

    return 0;
}

Copied!
  • Without volatile: The compiler might optimize the while (!buttonPressed) loop by assuming that buttonPressed never changes, because it doesn’t see any modification in the main program (This would cause the program to never exit the loop).
  • With volatile: The compiler always checks the real value of buttonPressed from memory, ensuring it detects changes made by external hardware.

Limitations and Considerations

The volatile modifier has been supported by C++ standards since its early versions and remains relevant in hardware-level and embedded systems programming.

But in modern applications, especially in multithreaded programming, std::atomic (and other synchronization primitives) are usually preferred for handling shared variables and safe synchronization between threads.