Importance Of Type Qualifiers And Storage Classes In C++.
In this Exclusive C++ Training Series, we will extend the topic of variables further and see type qualifiers and storage classes in C++ in this tutorial. Though this is a small topic, it is very important and significant as far as C++ programming is concerned.
The type qualifiers in C++ do not change the meaning of the variables or entities they are used with, rather they only add extra information to the entity.
Table of Contents:
Type Qualifiers In C++
Type qualifiers in C++ add extra properties to the variable like a variable being a constant or a volatile.
Type qualifiers express the way in which a variable is accessed or where a variable is stored in the memory by keeping the meaning or interpretation of the variable same. In a way, type qualifiers add more refinement to variables.
In C++, a type qualifier is specified just before the type specifier (data type) of the variable.
Type qualifiers in C++ are classified as shown below:
#1) const
Type specifier “const” is to define the objects of type const. A const object or variable cannot be modified once declared. If an attempt is made to modify const object or variable, then the compiler raises an error. We have already seen constants/literal in our previous tutorial.
The definition of constants using ‘const’ keyword corresponds to the type qualifier ‘const’.
#2) volatile
The type qualifier “volatile” means that the value of the variable marked volatile may be changed in other ways that are not specified by the program. The variables that are volatile change usually due to some external factors and not necessarily because of the program. In other words, they are volatile in nature.
For Example, a variable that reads the temperature in the real world can be made volatile as the reading temperature may not be completely controlled by the program.
#3) mutable
“mutable” type qualifier makes the members or variable modifiable.
The mutable qualifier is usually applied to non-static class members of non-const and non-reference type. As per specific situations, we might need some variables to remain immutable (cannot be changed) and some variables to be mutable. This type of qualifier is of much help when we want mutable characteristics.
Storage Classes In C++
So far, we have discussed all C++ variables in detail. We have seen that variables are declared with their respective data types and then used in the program. In order to fully define a variable, we also require storage classes apart from their data types.
Though we have not specified any storage classes till now for variables, there was a default storage class “auto” which was applied to all the variables.
So what are Storage Classes?
Storage classes specify how the variable or a function is to be treated by the compiler and how storage is to be allocated for a variable. It defines the visibility or scope and lifetime of a variable. The lifetime of the variable is how long the variable is going to remain active.
The visibility or scope of the variable is to which functions or modules the variable will be accessible. These storage classes are specified before the data type of variable.
In C++, we have the following storage classes:
#1) Auto Storage Class
This is the default storage class. The storage class “Auto” is applied to the local variables and is automatically assigned by the compiler to local variables. Local variables preceded by the ‘auto’ keyword remain active in the function in which they are declared and go out of scope once the function exits.
If the variables having an “auto” storage class are not initialized or assigned any value, then they have garbage or undefined values.
Let us see an example of auto variables in a C++ program.
#include <iostream> using namespace std; int main() { int i; float f; cout<<"Variable i = "<<i<<endl; cout<<"Variable f = "<<f<<endl; return 0; }
Output:
Variable i = 0
Variable f = 0
Now we can see that I and f are the two local variables that we have defined in the function main with the default storage class ‘auto’.
As we have not assigned any values to them, when we print these variables, we see that both have values = 0. This is entirely compiler dependent as to what values to assign auto local variables if they are not already assigned any value in the program.
NOTE: Starting from C++11, the auto keyword is used for type inference. This means that we can use a code like auto i=10 and the data type of I will be directly inferred from the initializer used for i. Hence, if we declare something like ‘auto float f;’, then the compiler is going to show an error.
So, we usually do not use declaration for storage class auto as it is implied that the default will always be auto storage class.
#2) Register Storage Class
When we have a requirement that a variable needs faster access, then we use the register storage class. So instead of storing the variables in Random Access Memory (RAM), these variables are stored in the CPU register and have a size equal to that of a register.
Additionally, as these variables do not have a memory location, we cannot use the ‘&’ operator with these variables.
Having a variable with a Register storage class does not guarantee that the variable will always be stored in the register. Instead, it just assumes that the variable may be stored in a register and is completely dependent on hardware and implementation.
Register variables have a scope and lifetime similar to auto variables.
For Example,
#include <iostream> using namespace std; int main() { int i; register float f; cout<<"Variable i = "<<i<<endl; cout<<"Variable f = "<<f<<endl; return 0; }
The above code with one register variable will give the same output as the one with an auto storage class.
Output:
Variable i = 0
Variable f = 0
#3) Extern Storage Class
The extern storage class is required when the variables need to be shared across multiple files. Extern variables have global scope and these variables are visible outside the file in which they are declared.
As extern variables are the variables declared and defined outside in another file they are not initialized.
Extern variables have global scope and the lifetime of extern variables is as long as the program in which it is declared as terminated.
Extern variables can be declared as follows:
extern int temp; int temp;
In the above example, we have two variable declarations with the same name but the first one is the extern variable defined elsewhere. This extern variable will be useful when we include the source file in which the extern variable temp is defined in our program.
#4) Static Storage Class
The static storage class tells the compiler to maintain the value of the variable throughout the lifetime of the program. Static variables are similar to the local variables but are preceded by a ‘static’ keyword.
Unlike local variables which go out of scope after the function exits, static variables do not go out of scope when a function or block exits, and their values are preserved between function calls.
Static variables are initialized and storage is allocated to them only once in the lifetime of a program. Static variables are initialized to 0 if not already initialized during declaration.
Let us see the following Example to better understand the Static Storage Class.
#include <iostream> using namespace std; void printvar() { static int var; var++; cout<<"static variable var = "<<var<<endl; } int main() { cout<<"printvar call 1: "; printvar(); cout<<"printvar call 2: "; printvar(); cout<<"printvar call 3: "; printvar(); cout<<"printvar call 4: "; printvar(); return 0; }
Output:
printvar call 1: static variable var = 1
printvar call 2: static variable var = 2
printvar call 3: static variable var = 3
printvar call 4: static variable var = 4
In the above code, we have a function ‘printvar’ in which we have declared a static variable var of type int. We then increment this variable and print it. In the main function, we call the printvar function four times.
Now check the output. The output shows that with every function call the static variable var is incremented by 1 from its previous value. This is the static storage class that helps the variable to maintain its value between function calls. The static variable is not reinitialized for every function call.
We should also notice that in the printvar function, we have just declared the static variable and not initialized it. It’s notable that when we do not initialize the static variables they are assigned with the initial value of 0.
Note: Static storage class can also be applied to global variables. In this case, the variable will have global scope and additional static storage.
#5) Mutable Storage Class
The mutable storage class is applied to the class objects only. By applying the mutable storage class, a member of an object can override the ‘const’ member function. This means a mutable member or object can be modified by a member function which is ‘const’.
We will learn more about the const functions & objects as well as mutable members in our later tutorials when we learn about object-oriented programming in C++.
Conclusion
This is all about type specifiers and storage classes in C++. We hope we were able to make all the concepts clear about storage classes and type specifiers through this tutorial.
In our upcoming tutorial, we will learn more about the various operators used in C++ along with their usage.
=> Check The Complete C++ Training Series Here