Part 5 — Chapter 23

Chapter 23: volatile Keyword in C

Introduction

The volatile keyword tells the compiler that a variable’s value may change unexpectedly at any time outside normal program control. Because of this, the compiler must always read the variable directly from memory instead of applying certain optimizations.

Without volatile, the compiler may assume the value never changes unexpectedly and reuse previously stored values, which can lead to incorrect program behavior.

Why volatile is Needed

Modern compilers optimize programs to improve execution speed. During optimization, the compiler may:

  • store variable values temporarily in CPU registers
  • skip repeated memory reads
  • remove what appears to be unnecessary access operations

For normal variables this is beneficial, but for hardware-related or asynchronously changing variables, these optimizations can become unsafe.

The volatile keyword prevents such optimization for a specific variable.

Syntax
volatile data_type variable_name;
Example Program
main.c
C
#include <stdio.h>

volatile int flag = 0;

int main()
{
    while(flag == 0)
    {
        // wait until flag changes
    }

    printf("Flag changed");

    return 0;
}
How It Works

The compiler is forced to read flag from memory every time the loop executes. Without volatile, the compiler might optimize the loop by assuming flag never changes, potentially creating an infinite loop.

Common Uses of volatile

The volatile keyword is commonly used for:

  • hardware registers
  • interrupt service routines (ISR)
  • shared variables between threads/tasks
  • status flags updated externally
  • memory-mapped peripheral access
volatile with Hardware Registers
volatile unsigned int *GPIO =
    (unsigned int *)0x40000000;

Here, the register value may change due to hardware activity, so every access must read directly from memory.

volatile vs Normal Variable

A side-by-side comparison outlining the key differences in compiler optimization and memory access behavior:

Standard Variable volatile Variable
Compiler may cache or optimize memory access Compiler reads directly from memory each time
Value assumed unchanged during execution Value may change unexpectedly
Faster optimization possible Prevents incorrect compiler optimization

Note: volatile does not make a variable thread-safe. It only forces the compiler to avoid unsafe optimization.

Important Points

  • volatile prevents unsafe compiler optimizations
  • The compiler always performs actual memory access for volatile variables
  • Frequently used with hardware registers and interrupts
  • Does not make variables thread-safe or atomic
  • Only affects compiler optimization behavior

Why This Matters in Embedded Systems

The volatile keyword is extremely important in embedded systems because hardware registers, interrupt flags, timers, and peripheral states can change independently of normal program execution.

volatile unsigned int *UART_STATUS;

Without volatile, the compiler may optimize away critical hardware reads, causing incorrect firmware behavior. Proper use of volatile helps ensure reliable communication between software and hardware.

← Chapter 22: Registers & Memory Mapping Chapter 24: Interrupt Basics →