Storage classes in C

storage classes in c

To completely define a variable, not only the ‘type’ of variable, the ‘storage class’ of the variable is also important. In other words, not only do variables have a data type, but also have ‘storage classes’.

Most often in our programs, we do not define the ‘Storage Classes’ of the variable. In such cases, if not specified during variable declaration, the compiler takes the default storage class based on the context in which it is used in the program.

What are storage classes?

Whenever variables are declared in the program, they are stored in either the CPU registers or the main memory. The Storage Classes here determine where the variable is stored among these.

The limit of the storage classes are not only up-to where the variable is stored,  but also it tells us:

  1. Where the variable would be stored.
  2. What will be the initial value of the variable, if initial value is not specifically assigned? (i.e. the default initial value).
  3. What is the scope of the variable; i.e. in which functions the value of the variable would be available.
  4. What is the life of the variable; i.e. how long would the variable exist.

There are 4 storage classes in C

  1. Automatic Storage Class
  2. External Storage Class
  3. Static Storage Class
  4. Register Storage Class
Storage class block diagram

Fig 1: Storage classes in C

Automatic Storage Class

As the name suggests, automatic storage class is a default storage class assigned by the compiler to any variable declared without a storage class. The features of the automatic storage class are given below.

 

StorageStack Memory
Default valueGarbage value
ScopeLocal to the block in which variable is defined.
LifeTill the control is with the block in which it is present.
Keywordauto

A variable is declared as automatic by adding a prefix to the variable called auto. Eg: auto int i.  The following program shows how an automatic Storage Class variable is declared, and the fact that if the variable is not initialized it contains garbage value. Example 1: Declaration of an auto variable

int main()
{
   auto int var;
   {
      printf ( "\n%d ", var ) ;
      return 0;
   }
}

The output of this code gives garbage values for all the printf statements. The garbage values change for every next execution of the code, as garbage values are unpredictable. Due to this, it is recommended to initialize the automatic Storage Class variables while declaration.

Also, ensure that the initialization is done in the right block, else it would result in unexpected outputs. There are three different examples illustrated below which explain the scope of the automatic Storage Class variables.

Example 2: Initialize in the beginning.

int main()
{
   auto int var = 4;
   {
      {
	     {
            printf ( "\n%d ", var ) ;
		 }
         printf ( "%d ", var ) ;
	  }
      printf ( "%d", var ) ;
   }
   printf ( "\n%d", var) ;
   return 0;
}

All the printf statements are executed and print the initialized value 4 since the variable is declared before all the blocks of printf statements.  If the declaration of a variable is shifted to the next block of code, the output throws an error. Execute the below code and observe that the declaration is in the third block of the code.

Example 3: Error due variable initialized later.

int main()
{
   {
      { 
         auto int var = 4;
         {
            printf ( "\n%d ", var ) ;
         }	
         printf ( "%d ", var ) ;
      }
      printf ( "%d", var ) ;
    }
	printf ( "\n%d", var) ;
return 0;
}

There will not be any output for the code, instead, it would lead to a compiler error saying ‘ variable var undeclared’. This is because the scope of the variable ‘var’ when used along with storage class ‘auto’,  is limited to the block in which it is declared. If there are blocks before the declaration, the compiler does not detect it and aborts the execution.
Consider the example 4 where variables are initialized in every block.

Example 4: Variable declared in every block

int main()
{ 
   auto int var = 4;
   {
      auto int var = 3;
      {
	     auto int var = 2;
         { 
		    auto int var = 1;
            printf ( "\n%d ", var ) ;
		 }
         printf ( "\n%d ", var ) ;
	   }
       printf ( "\n%d",var ) ;
   }
   printf ( "\n%d", var) ;
   return 0;
}

 

The above code gives the output as 1 2 3 4. The execution starts from the innermost block coming towards outside. The scope of the innermost ‘var’ is only up-to that block of code, hence it prints 1.  The ‘var’ in the next innermost block is initialized to 2, following next ‘var’ initialized to 3 and so on. Example 3 gives a complete definition regarding the scope of the variable declared as auto.

Note: Auto Storage Class is the default Storage Class for variables. If we do not mention the Storage Class for a variable, by default it is of type “auto

When to use auto storage class ?

If you don’t want to use any of the storage class as mentioned in the next post, then use the auto Storage Class. In fact most of the time we end up using the auto variables because often it so happens that once we have used the variables in a function we don’t mind losing them.

To use them, you do not have to mention the keyword “auto

External Storage Class

As the name suggests, the external storage class has its scope globally across various functions in the program and also on the files in the same directory.  The features of external SC are given below.

StorageMemory
Default valueZero
ScopeGlobal
LifeAs long as the program’s execution does not end
Keywordextern

The below example illustrates the scope of an extern variable.

Example 1

int count ;
main( )
{
  printf ( "\ncount = %d", count ) ;
    increment( ) ;
    increment( ) ;
    decrement( ) ;
    decrement( ) ;
}

increment( )
{
  count = count + 1 ;
  printf ( "\non incrementing count = %d", count ) ;
}

decrement( )
{
  count = count - 1 ;
  printf ( "\non decrementing count = %d", count ) ;
}

This program gives the output:

count = 0

on incrementing count = 1
on incrementing count = 2
on decrementing count = 1
on decrementing count = 0

 

Here it is obvious, that since the variable has extern Storage Class specified, all the functions have access to that variable. Hence when the first increment function is called, the counter increments by 1. Next, when decrement function is called, it retains the old value 1 and decrements 1 from it. Hence the new value is zero. The same is repeated again to get the final count value is zero.

Another example is illustrated where the difference between global and external variables is depicted.

Example 2

int global_var = 4;
int extern_var = 3;
int main()
{
  printf("\nThe value of the global_var is %d", global_var);
  extern int extern_var;
  printf("\nThe value of global_var and extern_var are %d , %d", global_var, extern_var);
}

The output of the above program would be

The value of the global_var is 4

The value of global_var and extern_var are 4, 3

 

Observe the difference in the declaration of the global and extern variables. Here both are global variables, and they would execute whenever they are present outside any function.

But the difference lies in
extern int extern_var;
int global_var = 4;

Here the first statement is a declaration, whereas the second is the definition. Whenever a variable is declared, space for it is reserved. Whereas, when it is defined, space gets reserved for it in memory. We had to declare extern_var since it is being used in printf( ) before it’s definition is encountered. There was no need to declare global_var since its definition is done before its usage.

When to use extern storage class?

Use extern Storage Class for only those variables that are being used by almost all the functions in the program. This would avoid unnecessary passing of these variables as arguments when making a function call. Declaring all the variables as extern would amount to a lot of wastage of memory space because these variables would remain active throughout the life of the program.

Static Storage class

As the name suggests, the variable defined with static storage class holds the last computed value in it. They don’t disappear when the function is no longer active. The features of the variable are given below.

StorageMemory
Default initial valueZero
ScopeLocal to the block in which the variable is defined
LifeThe value of the variable persists between different function calls
Keywordstatic

Example 1

int main( )
{
  increment( ) ;
  increment( ) ;
  increment( ) ;
return 0;
}

increment( )
{
  static int count = 1 ;
  printf ( "%d, ", count ) ;
  count = count + 1 ;
}

The output of the above program would be:

1, 2, 3

Observe that although the static variable is defined in increment function, it retains the value while switching back to the main function.  Initially, the value is 1, later an increment by leads count to be 2. When the control is taken back to the main function, the increment function is called another time. It retains the old value 1 and adds another 1 to it making it 2.

If the same program is written using variable defined as auto storage class, then observe that the output would be 1, 1, 1. This is because the life span of auto variables is only up to the function in which it is defined. When the main function calls the increment function for the second time, the variable is re-initialized to 1 again. So every time the variable count is tried to access, it has a value of 1.

Due to the ability of static variables to retains old values, It is recommended not to use any variable as static, unless and until it is really required. Because their values are kept in memory when the variables are not active, which means they take up space in memory that could otherwise be used by other variables.

Use static Storage Class only if you want the value of a variable to persist between different function calls.

When to use static storage class?

Use static storage class only if you want the value of a variable to persist between different function calls.

Register Storage Class

As the name suggests, for register Storage Class, the value defined in the variable is stored in the registers of the CPU. The features of the register storage class are given below.

StorageCPU registers
Default initial valueGarbage value
ScopeLocal to the block in which the variable is defined
LifeTill the control remains within the block in which the variable is defined
KeywordRegister

A value stored in a CPU register can always be accessed faster than the one that is stored in memory. Therefore, if a variable is used at many places in a program it is better to declare its storage class as register.

Example 1

int main()
{
  register int count;
  printf("\n%d",count);
  return 0;
}

The output of the program would be garbage value.
Sometimes it’s unpredictable, whether the count variable is really stored in CPU registers or not. This is because there are a limited number of CPU registers and may be involved in another task by storing values for that task. In such cases, the storage class by default is taken as auto.

For eg, if a processor is of 16bit, it cannot hold the values of float or double. In this case, the storage class would go by default as auto.

When to use register variables?

Variables that are being used very often in a program should be defined as register Storage Class. The reason is, there are very few CPU registers at our disposal and many of them might be busy doing something else. Make careful utilization of scarce resources. A typical application of register Storage Class is loop counters, which get used a number of times in a program.

 

Want to learn more about C and Embedded C? Follow the tutorial Series on YouTube – Master C and Embedded C Programming

Join the Course on Udemy to get a Certificate of Completion for C and Embedded C Programming.

Sharing is Caring!!

Leave a Reply

Your email address will not be published. Required fields are marked *