The volatile qualifier

Location
  1. Courses

    /

  2. Complete C++ Course

    /

  3. The basics

    /

  4. The volatile qualifier

What is the volatile qualifier?

The volatile qualifier is not often used, but it is worth being aware that it exists. C/C++ compilers do a great amount of optimizations when they compile C/C++ code to binary. Those optimizations might drastically change the nature of the code (But not its result). For example, a variable might be stored in a processor register only instead of the memory of the computer (In that case, it does not have a memory address. Therefore, the compiler may optimize a variable that way only if there is no line of code retrieving the address of the variable. Also, the variable must fit in a register). By defining a variable as volatile, the variable is guaranteed to be stored in the computer memory and all operations that change its value will directly assign its memory location with it (Instead of keeping it in a register or using its value instead, for example). Also, all operations on a volatile variable will be executed in the order they have been coded. For example, let us say we add the number 5 to a variable and then we add 7 to it. No matter the order those operations are executed in (var+5+7 or var+7+5), the result will be the same, so the compiler may decide to change the order of execution if it considers it is better. However, that may not happen with volatile variables.

Defining a volatile variable

A variable is defined as volatile by putting the keyword volatile, in its definition, before its type.

For example, in the code below:

1
2
3
4
5
6
7
8
9
int main() { int var = 50; volatile int var2 = 50; var2 += var; return 0; }

The variable var2 is guaranteed to be stored in the memory, but var might be replaced by its value, so the code above could be optimized as:

1
2
3
4
5
6
7
int main() { volatile int var2 = 50; var2 += 50; return 0; }

When is the volatile qualifier useful? Let us see an example:

1
2
3
4
5
6
7
int main() { char n = 25, n2 = 30; char * ptr = &n; return 0; }

Here, the address of the variable n has been retrieved, so we know it will be stored in the memory. Since n2 has been declared after n and they both weight 1 byte, we could assume n2 is stored in the memory address following the address of n. We could then try the following to change the value of n2:

ptr[1] = 100;

However, in that case, the variable n2 is actually not guaranteed to be stored in the memory. The variable n2 is not an array or a structure (That would not fit in a register) and its address has not been retrieved using the & operator, so it might be stored in a register instead of the memory (Or it might even be removed for the outputted binary code since it is not directly used). If this is the case, the line above change a memory location where we do not know what there is. To make sure that does not happen, a solution would be to declare n2 as a volatile variable.

1
2
3
4
5
6
7
8
9
10
int main() { char n = 25; voltile char n2 = 30; char * ptr = &n; ptr[1] = 100; // "n2" is set to 100. return 0; }

Note that accessing n2 that way is not a good practice. It has been done simply to illustrate the volatile qualifier.