Skip to content

Last updated:2026-10-12

C++ volatile Keyword

About the Author:

Personal WeChat official account:

wechat

1. volatile

Reading or writing a variable qualified with volatile triggers some observable side effects, and those observable side effects are determined by factors outside the program.

2. Applications of volatile

(1) Hardware registers of parallel devices (such as status registers). Suppose we want to initialize a device, and one of its registers is 0xff800000.

int  *output = (unsigned  int *)0xff800000; //定义一个IO端口;  
int   init(void)  
{  
    int i;  
    for(i=0;i< 10;i++)
    {  
    *output = i;  
    }  
}
After compiler optimization, the compiler decides the whole loop above is pointless and has no effect on the final result, because in the end the pointer output is just assigned 9 — so the code the compiler finally produces is equivalent to:
int  init(void)  
{  
    *output = 9;  
}
If the process of initializing this external device must assign values sequentially as in the code above, the optimization clearly fails to achieve the goal. Conversely, if instead of writing to this port repeatedly you read from it repeatedly, the result is the same: after optimization, the compiler may perform your code's reads from this address only once. Yet from the code's point of view there is nothing wrong. This is when volatile should be used to tell the compiler that this variable is unstable and must not be optimized when encountered. (2) A variable accessed inside an interrupt service routine;

static int i=0;

int main()
{
    while(1)
    {
    if(i) dosomething();
    }
}

/* Interrupt service routine */
void IRS()
{
    i=1;
}
The intent of the example above is that when an interrupt occurs, the interrupt service routine IRS handles it and changes the program variable i so that main calls the dosomething function. However, since the compiler sees that i is never modified inside main, it may perform the read from i into a register only once, and then every if check uses that "copy of i" in the register, so dosomething never gets called. If the variable i is qualified with volatile, the compiler guarantees that reads and writes of i are not optimized away, ensuring that after i is changed by an external program the change is promptly visible to the original program. (3) Variables shared by multiple tasks in multi-threaded applications. When several threads share a variable whose value can be changed by any one of them, it should be declared volatile. Its purpose is to prevent the compiler's optimization from loading the variable from memory into a CPU register, where a change made by one thread might not be synchronized to the other threads in time and cause program errors. volatile means the compiler must genuinely fetch the variable from memory on every access, instead of using the value already sitting in a register. Example:
volatile  bool bStop=false;  //bStop 为共享全局变量  
//第一个线程
void threadFunc1()
{
    ...
    while(!bStop){...}
}
//第二个线程终止上面的线程循环
void threadFunc2()
{
    ...
    bStop = true;
}
To terminate the first thread's loop from the second thread, if bStop is not defined with volatile the loop becomes an infinite one, because bStop has already been read into a register, and the register's copy of bStop never becomes FALSE. With volatile, each iteration reads bStop's value from memory, and there is no infinite loop.

Knowing the application scenarios of volatile is an effective way to distinguish C/C++ programmers from embedded developers: embedded folks constantly deal with hardware, interrupts, RTOSes and so on, all of which require volatile variables. Not understanding volatile invites disaster in program design.

3. Common volatile Questions

The questions below show whether an interviewee truly understands volatile. (1) Can a parameter be both const and volatile? Why? Yes. One example is a read-only status register. It is volatile because it may be changed unexpectedly. It is const because the program should not try to modify it. (2) Can a pointer be volatile? Why? Yes, although this is not common. One example is when an interrupt service routine modifies a pointer that points to a buffer. (3) What is wrong with the following function?

int square(volatile int *ptr) 
{ 
return *ptr * *ptr; 
} 
This code is a bit devious. Its intent is to return the square of the value pointed to by ptr, but since ptr points to a volatile parameter, the compiler will produce something like the following:
int square(volatile int *ptr) 
{ 
int a,b; 
a = *ptr; 
b = *ptr; 
return a * b; 
} 
Since the value of *ptr may change unexpectedly, a and b may be different. As a result, this code may not return the square you expect! The correct code is as follows:
long square(volatile int *ptr) 
{ 
int a=*ptr; 
return a * a; 
} 

4. Using volatile

  • The volatile keyword is a type modifier; a variable declared with it can be changed by factors unknown to the compiler (the operating system, hardware, other threads, etc.). Use volatile to tell the compiler not to optimize such objects.

  • A variable declared volatile must be read from memory on every access (a variable not qualified with volatile may be read from a CPU register because of compiler optimization)

  • const can be volatile (e.g. a read-only status register)
  • Pointers can be volatile

Code to study:

Comments