Table of Contents
Understanding “Volatile” Qualifier In C Set 2 (Examples)
The “volatile” keyword is used to prevent the compiler from optimizing objects whose values can change unpredictably, usually due to external factors. When an object is declared as volatile, the compiler ensures that its value is always read from memory, even if it appears redundant, to avoid potential issues caused by optimizations. This is crucial for ensuring the correct behavior of objects that can change independently of the program’s logic.
1) Global variables modified by an interrupt service routine outside the scope:
Global variables modified by an interrupt service routine (ISR) often require the “volatile” keyword. For instance, when dealing with data ports, declaring a variable as “volatile” ensures that the compiler doesn’t optimize the code to read the port just once and cache the value. Instead, it forces the code to always fetch the latest data from the port. ISRs are typically used to update these variables when new data arrives due to interruptions, maintaining data accuracy in real-time applications.
2) Global variables within a multi-threaded application:
When multiple threads share information using global variables, it’s essential to mark these variables as “volatile.” This ensures that updates made by one thread are always freshly fetched by others. Without “volatile,” the compiler might optimize by caching the values, which can lead to synchronization issues in asynchronous thread execution. Using “volatile” nullifies these compiler optimizations, making global variables suitable for safe inter-thread communication.
If we do not use the volatile qualifier, the following problems may arise:
1) Code may not work as expected when optimization is turned on.
2) Code may not work as expected when interrupts are enabled and used.
Example- To illustrate the compilers interpret volatile keyword
In the program below, We are changing the value of a const object with the pointer and also compiling code without an optimization option. Therefore, the compiler won’t do any optimization and will change the value of the const object.
/* Compile code without optimization option */
#include <stdio.h>
int main(void)
{
const int local = 10;
int *ptr = (int*) &local;
printf("Initial value of local : %d \n", local);
*ptr = 100;
printf("Modified value of local: %d \n", local);
return 0;
}
- Preprocessed Code: This file has the “.i” extension and contains the code after preprocessing, which includes macro expansions, file inclusions, and other preprocessing directives. It’s often a human-readable form of the code that’s processed by the compiler.
- Assembly Code: The assembly code file has the “.s” extension and contains the code translated into assembly language. This code is closer to the low-level machine instructions and is often specific to the target architecture for which the code is being compiled.
- Object Code: The object code file has the “.o” extension and contains the code in a binary format that is not human-readable. It’s generated after the compilation and assembly stages and is ready to be linked into an executable program.
Output
[narendra@ubuntu]$ gcc volatile.c -o volatile –save-temps
[narendra@ubuntu]$ ./volatile
Initial value of local : 10
Modified value of local: 100
[narendra@ubuntu]$ ls -l volatile.s
-rw-r–r– 1 narendra narendra 731 2016-11-19 16:19 volatile.s
[narendra@ubuntu]$
Compile The Same code with the optimization option (i.e. -O option)
In the given code, there’s a variable called “local” that’s marked as “const,” which means it can’t be changed after it’s set. The GCC compiler is smart and doesn’t execute any instructions that try to change the value of this “const” variable. So, the value of the “const” variable stays the same throughout the program.
/* Compile code with optimization option */
#include <stdio.h>
int main(void)
{
const int local = 10;
int *ptr = (int*) &local;
printf("Initial value of local : %d \n", local);
*ptr = 100;
printf("Modified value of local: %d \n", local);
return 0;
}
Output
[narendra@ubuntu]$ gcc -O3 volatile.c -o volatile –save-temps
[narendra@ubuntu]$ ./volatile
Initial value of local : 10
Modified value of local: 10
[narendra@ubuntu]$ ls -l volatile.s
-rw-r–r– 1 narendra narendra 626 2016-11-19 16:21 volatile.s
When a variable is declared as both const
and volatile
, it indicates to the compiler that the value of the variable can change at any time due to external factors and, therefore, should not be subject to optimizations. Even when you compile the code with optimization options, the value of the const
and volatile object can change because the volatile qualifier instructs the compiler not to perform any optimizations that might prevent or alter changes to the variable. This combination is useful when you want to ensure that a variable remains accessible and up-to-date in situations where the value can change unexpectedly, even in optimized code.
/* Compile code with optimization option */
#include <stdio.h>
int main(void)
{
const volatile int local = 10;
int *ptr = (int*) &local;
printf("Initial value of local : %d \n", local);
*ptr = 100;
printf("Modified value of local: %d \n", local);
return 0;
}
Output
[narendra@ubuntu]$ gcc -O3 volatile.c -o volatile –save-temp
[narendra@ubuntu]$ ./volatile
Initial value of local : 10
Modified value of local: 100
[narendra@ubuntu]$ ls -l volatile.s
-rw-r–r– 1 narendra narendra 711 2016-11-19 16:22 volatile.s
[narendra@ubuntu]$
Think of the touch sensor on a mobile phone. The software that handles the touch sensor should do two things:
- It should promise not to change the location where you touch, ensuring the data’s integrity. That’s the “const” part.
- It should always read the touch input as if it’s brand new, as touch data changes all the time. This is the “volatile” part.
So, for the touch sensor driver, it’s crucial to handle touch data in a “const volatile” manner, which guarantees accuracy and responsiveness to changing touch inputs.
FAQ- Understanding “Volatile” Qualifier In C | Set 2 (Examples)
Q1. What is a volatile qualifier in C?
Ans. “Volatile” is a label you can give to a variable when you declare it. It tells the compiler that the variable’s value might change at any time without the program’s knowledge or control. This means the compiler should be cautious about optimizing or caching the variable, as it can change unexpectedly.
Q2. What is the use of volatile in the C example?
Ans. Example. The code snippet below is of using ‘volatile’ used to declare a variable in C: volatile int *p = (volatile int *) 0x1000; // declare a volatile pointer to an address in memory. volatile int x = 0; // declare a volatile integer variable.
Q3. What are volatile type qualifiers?
Ans. The “volatile” qualifier is used to declare a data object that can have its value changed in ways that are beyond the control or detection of the compiler. This includes situations where a variable’s value may be updated by external factors like the system clock or another program.
Hello, I’m Hridhya Manoj. I’m passionate about technology and its ever-evolving landscape. With a deep love for writing and a curious mind, I enjoy translating complex concepts into understandable, engaging content. Let’s explore the world of tech together