Tuesday, January 12, 2016

C Qualifiers - Constant and Volatile type Qualifier

C has some basic data types like 'int', 'float', 'char' etc. Each of which can hold a data of a specific type and has a set of specific properties defined for them. But what if you need to modify the properties of them? For example, if you want to make an 'int' variable constant, that means it's value shouldn't be changed from any where else in the program except the variable definition part. C type qualifiers can be used for such purposes.

'Const' Qualifier in C

Two type qualifiers available in C are 'const' and 'volatile'.
'Const' qualifier will impose a restriction on the variable, such a way that its value can't be changed or modified. The main use of 'const' is to define constants in your program; so that it's values can't be changed. Please take a look at the example given below to understand the use case of 'const' qualifier
  1. #include <stdio.h>
  2. // PI is defined as 'const' so that you may not change it's value accidentally.
  3. const float PI = 3.14;
  4.  
  5. double find_area(float radius) {
  6. return PI * radius * radius;
  7. }
  8.  
  9. int main() {
  10. printf("Area: %f", find_area(5.5));
  11. return 0;
  12. }
  13.  
  14. Output:
  15. Area: 94.985001

'Volatile' Type Qualifier in C

If a variable is declared as 'volatile', its value can be changed from outside the program. Declaring a variable with 'volatile' is actually a hint to the compiler to not perform any optimizations on the access restrictions of the variable. Let's take a look at it with the help of an example using 'volatile' keyword.

  1. #include <stdio.h>
  2. int has_signalled = 0;
  3. int wait_for_signal(void)
  4. {
  5. while (has_signalled == 0) {
  6. }
  7. return 1;
  8. }
  9. int main() {
  10. if(wait_for_signal() == 1) {
  11. printf("Signalled!");
  12. }
  13. return 0;
  14. }
In the above code, imagine the value of variable 'has_signalled' is changed from some other part of code (through pointer or some other way). When you compile the above code, compiler might think that value of 'has_signalled' is not changed and will ignore the while loop. Another issue is, if the above code is running in multi-threaded environment on a multiprocessor system with each thread allocated to different process, system may cache the value of 'has_signalled' variable in one of the registers for optimal performance because, memory access is slower than register access. This would make the 'while' loop infinite. To get rid of above unwanted issues due to compiler optimization, we can define the variable as given below.
  1. #include <stdio.h>
  2. volatile int has_signalled = 0;
  3. int wait_for_signal(void)
  4. {
  5. while (has_signalled == 0) {
  6. }
  7. return 1;
  8. }
  9. int main() {
  10. if(wait_for_signal() == 1) {
  11. printf("Signalled!");
  12. }
  13. return 0;
  14. }
Now the value for 'has_signalled' will always be read from the memory location instead of any temporary register.
Volatile can be helpful in the following scenarios. 
  • When value of a global variable represent memory mapped port. By making such a variable as volatile, we can be sure that we will always get the latest value from the port.
  • When you run multi-threaded applications, volatile can prevent some of the synchronization issues
'Volatile' and 'Const' together
Let's see another situation where volatile qualifier is extremely useful. Imagine you have a variable representing a buffer which is filled by another device/process. How would you make this buffer variable unchanged and prevent caching of it at the same time? You can declare the variable as 'const volatile' or 'volatile const'. By doing this, compiler will prevent changing the buffer which represents the variable at the same time, value of the buffer will not get cached.

No comments: