Volatile in C
Introduction
A volatile keyword is a qualifier in C. Qualifiers are nothing but keywords which are used to modify the properties of a variable.
Qualifiers are of two types:
1) Const
The const type qualifier declares an object/variable to be nonmodifiable. But, Optimization can be done on it.
2) Volatile
Volatile is a qualifier and a variable should be declared volatile whenever its value could change unexpectedly and no optimization is done on it.
The concept of volatile is somehow not understood well by many programmers and the main reason behind this could be the lack of real-world use of this keyword in typical C programs. The programs in C are obviously high level, but the point to consider here is that volatile plays a key role in Embedded C Coding which is simply an extension of C language used for development of microcontroller-based applications.
Definition of volatile
A volatile is a qualifier in C which basically prevents the compiler from performing any kind of optimization on the targeted object that can change in ways that the compiler cannot determine.
In simple terms, a variable declared as volatile is a volatile variable
- That can change unexpectedly
- No assumption regarding its value can be made by the compiler
Declaration of volatile
Syntax : volatile data_type variable name; OR
volatile data_type *variable_name;
Eg:
volatile int p;
volatile int *p;
Let’s understand this keyword with the help of a program;
Program 1: C program without the use of volatile qualifier
#define MEMORY_ADDRESS 0x1000U
int main(void)
{
int val = 0;
int *v = (int *) MEMORY_ADDRESS;
while(1)
{
val = *v;
if (val)
break;
}
return 0;
}
Code Explanation:
The above code works fine and will give the desired results if there are no optimizations performed by the compiler.
The piece of code will always go and read the value(val) stored at the address pointed by the pointer ‘v’.
But what happens if the compiler optimization occurs here?
If the compiler optimization occurs here and the value is updated by DMA or interrupt which is not under the scope of the compiler, then the compiler optimizes it by keeping a copy of the first read value. The value is kept here in order to avoid multiple memory read operations which are basically time consuming.
What is to understand here is that, in case the value at this address changes then it will never be updated here.
How to avoid this?
In order to avoid this, we need to explicitly inform the compiler that the pointer ‘v’ is volatile and hence the compiler must not optimize it or perform optimization on that pointer.
Program 2: C program with the use of volatile qualifier
#define MEMORY_ADDRESS 0x1000U
int main(void)
{
int val = 0;
volatile int *v = (int *) MEMORY_ADDRESS; //declaring the variable as volatile
while(1)
{
val = *v;
if (val)
break;
}
return 0;
}
Code Explanation:
In the above code, we introduce the volatile keyword before declaring the pointer ‘v’. By doing this, we are explicitly telling the compiler that the pointer ‘v’ is volatile and hence the compiler must not optimize it.
Consequences of frequent use of volatile
Volatile qualifier may solve the problem of unwanted optimization done by the compiler but we must keep in mind the consequences that it brings with frequent usage.
The volatile variable forces the compiler to not keep a copy of values and fetch a fresh value from memory every time which takes more clock cycles, i.e., more time complexity.
Hence, it is always recommended that a variable should be declared volatile when the value of that variable could change unexpectedly.