Storage classes in C


Reading time: 25 minutes | Coding time: 5 minutes

A Storage Class defines the scope (visibility) and life-time of variables and/or functions within a C Program. They precede the type that they modify.

In other words, Storage Classes are used to describe the features of a variable/function. These features basically include the scope, visibility and life-time which help us to trace the existence of a particular variable during the runtime of a program.These specifiers are the keywords which can appear next to the top-level type of a declaration. The use of these keywords affects the storage duration and linkage of the declared object, depending on whether it is declared at file scope or at block scope

Simply, In C language, each variable has a storage class which decides the following things:

  • scope i.e where the value of the variable would be available inside a program.
  • default initial value i.e if we do not explicitly initialize that variable, what will be its default initial value.
  • lifetime of that variable i.e for how long will that variable exist.

The following storage classes are most oftenly used in C programming :

  1. Automatic variables
  2. External variables
  3. Static variables
  4. Register variables

Automatic variables: auto

Scope: Variable defined with auto storage class are local to the function block inside which they are defined.

Default Initial Value: Any random value i.e garbage value.

Lifetime: Till the end of the function/method block where the variable is defined.

A variable declared inside a function without any storage class specification, is by default an automatic variable. They are created when a function is called and are destroyed automatically when the function's execution is completed. Automatic variables can also be called local variables because they are local to a function. By default they are assigned garbage value by the compiler.

Auto variables can be only accessed within the block/function they have been declared and not outside them (which defines their scope). Of course, these can be accessed within nested blocks within the parent block/function in which the auto variable was declared. However, they can be accessed outside their scope as well using the concept of pointers given here by pointing to the very exact memory location where the variables resides.

Example 1 :-

#include <stdio.h>  
int main()  
{  
 int a; //auto  
 char b;  
 float c;   
 printf("%d %c %f",a,b,c); // printing initial default value of automaticvariables a, b, and c.   
 return 0;  
}  

Output 1 :-

garbage garbage garbage 

Example 2 :-

#include <stdio.h>  
int main()  
{   
  int a = 10,i;   
  printf("%d ",++a);  
 {  
   int a = 20;   
   for (i=0;i&lt;3;i++)  
   {  
     printf("%d ",a); // 20 will be printed 3 times since it is the local value of a    }  
 }  
  printf("%d ",a); // 11 will be printed since the scope of a = 20 is ended.   
}  

Output 2 :-

11 20 20 20 11

External or Global variable extern

Scope : Global i.e everywhere in the program. These variables are not bound by any function, they are available everywhere.

Default initial value : 0(zero).

Lifetime : Till the program doesn't finish its execution, you can access global variables.

A variable that is declared outside any function is a Global Variable.
The external storage class is used to tell the compiler that the variable defined as extern is declared with an external linkage elsewhere in the program.
Global variables remain available throughout the program execution. By default, initial value of the Global variable is 0(zero).
One important thing to remember about global variable is that their values can be changed by any function in the program.
The variables declared as extern are not allocated any memory.
It is only declaration and intended to specify that the variable is declared elsewhere in the program.
We can only initialize the extern variable globally, i.e., we can not initialize the external variable within any block or method.
An external variable can be declared many times but can be initialized at only once.
If a variable is declared as external then the compiler searches for that variable to be initialized somewhere in the program which may be extern or static. If it is not, then the compiler will show an error.

NOTE :- Declaring the storage class as global or external for all the variables in a program can waste a lot of memory space because these variables have a lifetime till the end of the program. Thus, variables, which are not needed till the end of the program, will still occupy the memory and thus, memory will be wasted.

Example - 1 :-

#include <stdio.h>  
int main()  
{  
   extern int a;   
   printf("%d",a);  
}  

Output 1 :-

main.c:(.text+0x6): undefined reference to `a'
collect2: error: ld returned 1 exit status 

Example 2 :-

#include <stdio.h> 
int a;   
int main()  
{  
    extern int a; // variable a is defined globally, the memory will not be allocated to a  
    printf("%d",a);  
}  

Output 2 :-

0 

Static variables: static

Scope : Local to the block in which the variable is defined

Default initial value : 0(Zero).

Lifetime : Till the whole program doesn't finish its execution.

A static variable tells the compiler to persist/save the variable until the end of program.
Instead of creating and destroying a variable every time when it comes into and goes out of scope, static variable is initialized only once and remains into existence till the end of the program.
A static variable can either be internal or external depending upon the place of declaration.
Scope of internal static variable remains inside the function in which it is defined.
External static variables remain restricted to scope of file in which they are declared.

They are assigned 0 (zero) as default value by the compiler.The variables defined as static specifier can hold their value between the multiple function calls.

Example - 1 :-

#include <stdio.h>    
static char c;  
static int i;  
static float f;   
static char s[100];  
void main ()  
{  
    printf("%d %d %f %s",c,i,f); // the initial default value of c, i, and f will be     printed.   
} 

Output 1 :-

0 0 0.000000 (null)

Example 2 :-

#include <stdio.h>
void sum()  
{  
   static int a = 10;  
   static int b = 24;   
   printf("%d %d \n",a,b);  
   a++;   
   b++;  
}  
void main()  
{  
    int i;  
    for(i = 0; i&lt;3; i++)  
    {   
      sum(); // The static variables holds their value between multiple function     calls.    
     }  
}  

Output 2 :-

10 24 
11 25 
12 26 

Register variable: register

Scope : Local to the function in which it is declared.

Default initial value : Any random value i.e garbage value

Lifetime: Till the end of function/method block, in which the variable is defined.

Register variables inform the compiler to store the variable in CPU register instead of memory.

Register variables have faster accessibility than a normal variable.
Generally, the frequently used variables are kept in registers. But only a few variables can be placed inside registers.

One application of register storage class can be in using loops, where the variable gets used a number of times in the program, in a very short span of time.
We can not dereference the register variables, i.e., we can not use &operator for the register variable.

The register keyword is used for the variable which should be stored in the CPU register. However, it is compiler's choice whether or not; the variables can be stored in the register.

We can store pointers into the register, i.e., a register can store the address of a variable.

Static variables can not be stored into the register since we can not use more than one storage specifier for the same variable.
NOTE: We can never get the address of such variables.

Example 1 :-

#include <stdio.h>  
int main()  
{  
    register int a; // variable a is allocated memory in the CPU register. The initial default value of a is 0.   
    printf("%d",a);  
}  

Output 1 :-

0

Example 2 :-

#include <stdio.h>  
int main()  
{  
   register int a = 0;   
   printf("%u",&a); // This will give a compile time error since we can not access the address of a register variable.   
}  

Output 2 :-

main.c:5:5: error: address of register variable ?a? requested
printf("%u",&a);  ^~~~~~

Which storage class should be used and when?

To improve the speed of execution of the program and to carefully use the memory space occupied by the variables, following points should be kept in mind while using storage classes:

  • We should use static storage class only when we want the value of the variable to remain same every time we call it using different function calls.

  • We should use register storage class only for those variables that are used in our program very oftenly. CPU registers are limited and thus should be used carefully.

  • We should use external or global storage class only for those variables that are being used by almost all the functions in the program.

  • If we do not have the purpose of any of the above mentioned storage classes, then we should use the automatic storage class.