What is volatile (type qualifier)?

A C type qualifier that tells the compiler that a variable's value may change outside the program's view (by a peripheral, an interrupt handler and so on), or that the accesses themselves matter. Accesses to a volatile object are not removed or merged; they are performed as many times and in the order written. It is used for memory-mapped I/O registers and for flags shared with interrupt handlers. It does not make operations atomic or guarantee ordering with respect to other cores.

Japanese name: volatile(型修飾子)

volatile (type qualifier) appears in 7 practice questions across 6 topics, including C Programming Basics, OS & Hardware, Multicore & Synchronization.

Field: C Programming Basics

What happens without it

In a loop such as while (flag == 0) { }, if only an interrupt handler changes flag, the compiler may decide that flag cannot change inside the loop, read it once and produce an infinite loop. The same can happen in a loop waiting on a peripheral status register, and consecutive writes to the same register may be merged into one. With volatile, the reads and writes are actually performed as many times as written in the code.

Reading the declarations

volatile uint32_t *p is a "pointer to volatile uint32_t", so accesses to *p are not removed. volatile uint32_t *const p adds the meaning that the pointer itself cannot be changed (it always points to the same register). Macros that convert an address into a pointer and dereference it, as in #define REG (*(volatile uint32_t *)0x40020014), are also widely used.

What volatile does not do

volatile does not make a read-modify-write operation atomic, so an interrupt in the middle of *reg |= mask; can make another bit's change disappear. A value too wide to be read or written at once, such as a 32-bit variable on an 8-bit microcontroller, can be read half-updated if an interrupt occurs in between. For synchronization between threads, mechanisms that guarantee atomicity and ordering, such as C11 _Atomic or locks, are used.

Try it: questions about volatile (type qualifier)

In C, why is marking a flag variable shared between threads volatile not sufficient for synchronization?

  1. AA volatile variable can no longer be read by other threads
  2. Bvolatile only restrains compiler optimizations and guarantees neither atomicity nor the order in which other cores see operations
  3. CA volatile variable is stored on disk and becomes slow
Show answer and explanation

Answer: B. volatile only restrains compiler optimizations and guarantees neither atomicity nor the order in which other cores see operations

volatile tells the compiler not to omit or merge reads and writes of a variable; it was designed for accessing hardware registers. It does not stop the CPU from reordering memory operations, and it does not make operations such as counter++ atomic. Since C11 and C++11, _Atomic and std::atomic guarantee both atomicity and memory ordering.

FAQ

Can const and volatile be used together?

Yes. const volatile means "the program does not modify it, but it changes for outside reasons, so read it again every time", and is used for read-only status registers and the like.

Does volatile make code slower?

For that variable, the optimization of keeping its value in a register is no longer possible, so accesses increase and the code can become slower. For that reason it is applied only where needed, such as peripheral registers and variables shared with interrupt handlers, rather than to every variable.

volatile (type qualifier) in the explanations

Questions that mention volatile (type qualifier) (7)

  1. When reading a device status register via memory-mapped I/O as above, why is it declared volatile and the region configured as uncached?
  2. In C, why is marking a flag variable shared between threads volatile not sufficient for synchronization?
  3. In microcontrollers and similar devices, which scheme assigns peripheral registers to the same address space as memory and operates them with ordinary memory read/write instructions?
  4. When the program above is compiled with optimization, led_on() may never be called even after the timer interrupt fires. Which pairs the cause with the fix correctly?
  5. In embedded programs, variables that hold the value of a 32-bit peripheral register are often declared with uint32_t from stdint.h rather than unsigned int. Which of the following is the main reason?
  6. A microcontroller output register is declared and used as above. Which of the following correctly describes this declaration?
  7. Timing a small loop like the one above gave nearly zero time even for large N. What is the most likely cause?

Books on C Programming Basics Ad

As an Amazon Associate I earn from qualifying purchases.

Related terms

Variable Memory-mapped I/O Interrupt handler Interrupt Modulo operation Microcontroller (MCU) Pointer Microbenchmark Alignment and padding Bit-field

Back to the glossary