Horizontal Advertisement Banner
Advertisement


Introduction to Storage Classes:





In the C programming language, storage classes are used to define the scope and lifetime of variables.

There are four main storage classes in C:

  • auto
  • register
  • static
  • extern

why storage classes are necessary.

Storage classes in C are necessary because they provide a way to control the scope, visibility, and lifetime of variables in a program. They offer a mechanism for programmers to tailor the behavior of variables based on the specific requirements of different parts of the code. Here are several reasons why storage classes are necessary in C:

Scope Management:

Storage classes help define the scope of a variable, determining where in the code the variable is accessible. For example, local variables with the auto storage class are limited to the scope of the function or block in which they are declared.

Lifetime Control:

Storage classes influence the lifetime of variables, dictating how long a variable persists in memory. For instance, static variables retain their values between function calls, maintaining state across invocations.

Memory Efficiency:

By allowing variables to be stored in different memory locations (such as registers with register or in a fixed memory location with static), storage classes enable programmers to optimize memory usage based on the specific needs of the variable.

Linkage and Visibility:

Storage classes provide a way to manage the linkage and visibility of variables. For example, extern variables can be declared in one file and defined in another, facilitating the sharing of variables across different parts of a program.

Performance Optimization:

The register storage class suggests to the compiler that a variable should be stored in a CPU register for faster access. This can result in performance improvements, especially for frequently accessed variables.

State Retention:

Storage classes like static are crucial for maintaining state across function calls. They allow variables to retain their values, providing a means to preserve information between different invocations of a function.

Code Modularity:

Storage classes contribute to code modularity by allowing variables to be encapsulated within specific functions or files. This helps in organizing and structuring code, making it more maintainable and understandable.

Multiple File Support:

Storage classes, particularly extern, enable the creation of multi-file programs. They allow variables to be shared between different source files, facilitating collaboration on larger projects.

Resource Management:

Storage classes are instrumental in managing resources efficiently. For example, variables with automatic storage duration (auto) are automatically deallocated when they go out of scope, helping in resource management.



Horizontal Advertisement Banner
Advertisement


Moreover, a variable's storage class tells us about the following characteristics:

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



1. Automatic Storage Class in Programming Languages


The "automatic" storage class in programming languages refers to variables that are automatically allocated and deallocated memory space within a specific block or scope.

Key characteristics of automatic storage class:

  • Allocation and Deallocation: Memory for automatic variables is allocated when the block is entered and deallocated when the block is exited.
  • Default for Local Variables: If you declare a variable within a function without specifying a storage class, it is considered to have automatic storage class by default.
  • Limited Scope: The scope of automatic variables is limited to the block in which they are declared.
  • No Default Initialization: Automatic variables do not have a default initial value. Their initial values are undefined unless explicitly initialized.


Example in C:

Automatic variables are not initialized by default, so their values are undefined. This can lead to unexpected behavior. To avoid this, explicitly initialize the variables with a desired value.



#include <stdio.h>

int main() {
  // Initialize i and j to 0
  auto int i = 0, j = 0;

  printf("\n%d %d", i, j);

  return 0;
}
Output:
    0 0


Scope and life of an automatic variable is illustrated in the following program.

#include <stdio.h>
int main() {

      auto int i = 1 ;
      {
          {
              {
                  printf ( "\n%d ", i ) ;
              }
              printf ( "%d ", i ) ;
          }
          printf ( "%d", i ) ;
      }
  }
Output:
1 1 1


Horizontal Advertisement Banner
Advertisement


Explain the scope of each variable 'i' within the program.

#include <stdio.h>
void main( )
  {
      auto int i = 1 ;
      {
          auto int i = 2 ;
          {
              auto int i = 3 ;
              printf ( "\n%d ", i ) ;
          }
          printf ( "%d ", i ) ;
      }
      printf ( "%d", i ) ;
  }
3 2 1


Describe the storage class of the variable x in the exampleFunction. How does this storage class affect the scope and lifetime of the variable?

#include <stdio.h>

void exampleFunction() {
  int x = 10; // Automatic storage class
  printf("The value of x is: %d\n", x);
} // 'x' is automatically deallocated when the function exits

int main() {
  exampleFunction(); // 'x' is not accessible here, as it was local to exampleFunction
  return 0;
}
Output:
The value of x is: 10

In the example above, x is an automatic variable with a scope limited to the exampleFunction.



Register Storage Class



The register storage class in C is a specifier that suggests to the compiler that the variable should be stored in a CPU register for quicker access. Here are the key features of a variable defined with the register storage class:

  • Storage: Variables declared with the register storage class are stored in CPU registers instead of RAM. Registers are faster to access than RAM, so using the register specifier is a way to optimize performance.
  • Default Initial Value: Like automatic variables, the default initial value of a register variable is garbage. It is not explicitly initialized by default, so its initial value is undefined until assigned a specific value by the program.
  • Scope: The scope of a register variable is local to the block in which it is defined. It is not accessible outside that block.
  • Lifetime: The lifetime of a register variable is tied to the control flow within the block in which it is defined. It is created when the control enters the block and ceases to exist when the control exits that block.
  • Limited Number of Registers: The number of available CPU registers is limited, and the compiler may choose to ignore the register specifier. Modern compilers are often good at optimizing register usage, and in many cases, they may ignore the register specifier and make their own decisions about register allocation.


Here's an example of using the register storage class:
#include <stdio.h>

int main() {
register int x; // Declare x as a register variable
                
// The following line may or may not result in a register allocation
x = 10;
                
printf("The value of x is: %d\n", x);
                
return 0;
}


Note: The use of the register keyword is not as common or necessary as it once was. Modern compilers are sophisticated enough to optimize register allocation without explicit hints from the programmer. In fact, the register keyword is often ignored by compilers today.


Here are some additional things to keep in mind about register variables:
  • They can only be used for simple data types such as integers, floats, and pointers.
  • They cannot be used for arrays or structures.
  • They cannot be initialized with constant values.
  • They cannot be declared as static or extern.


Horizontal Advertisement Banner
Advertisement


Static Storage Class



In C programming, the static storage class is used to define variables with a lifespan that extends throughout the entire program execution. A variable declared as static retains its value between function calls and is allocated storage in the data segment of the program. The scope of a static variable is limited to the block or function in which it is declared, or, if declared at the file level, it is visible only within that file. If not explicitly initialized, static variables are automatically initialized to zero.


Here's an overview of the static storage class in C:


  • Storage Duration:Variables declared as static have a lifespan that extends throughout the entire program execution. They are allocated storage in the data segment of the program.
  • Scope:The scope of a static variable is limited to the block or function in which it is declared.If declared at the file level (outside any function), the scope is limited to the file where it is declared.
  • Initialization:By default, static variables are initialized to zero if no explicit initialization is provided.If initialized, the value persists across function calls.
  • Visibility:If a static variable is declared within a function, it is visible only within that function.If declared at the file level, it is visible only within that file.
  • Default Value:If not explicitly initialized, static variables are automatically initialized to zero.


Static variables persist throughout the entire duration of the program's execution.

#include<stdio.h>

void  increment( )
{
static int i = 1 ;
printf ( "%d\n", i ) ;
i = i + 1 ;
}
    
void  main( )
   {
    increment( ) ;
    increment( ) ;
    increment( ) ;
    }
Output:
1
2
3


Dynamic variables have a lifespan that is not persistent throughout the entire duration of the program's execution.

#include<stdio.h>

void  increment( )
{
 int i = 1 ;
printf ( "%d\n", i ) ;
i = i + 1 ;
}
    
void  main( )
   {
    increment( ) ;
    increment( ) ;
    increment( ) ;
    }
Output:
1
1
1


Horizontal Advertisement Banner
Advertisement


External Storage Class

The extern storage class in C, which is used to declare variables and functions that are defined in other files. The extern keyword informs the compiler that the variable or function is declared elsewhere, and the actual definition will be provided at link time.

The features of a variable whose storage class has been defined as external are as follows:

  • Storage: The variable's value is stored in memory.
  • Default value: When declared at the global scope or outside of any function, the default initial value for such a variable is zero if it's not explicitly initialized.
  • Scope: The variable is accessible from any part of the program, i.e., it has a global scope.
  • Lifetime: The variable exists for the entire duration of the program's execution, from the moment the program starts running until it terminates. Thus, its lifetime extends throughout the execution of the program.

External variables differ from those previously discussed in that they possess a global scope rather than a local one. They are declared outside of all functions yet remain accessible to any function that wishes to utilize them. Here's an example to illustrate this distinction.

#include <stdio.h>
int i;

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

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

int main()
{
    printf("\ni = %d", i);
    increment();
    increment();
    decrement();
    decrement();
}
Output:
i = 0
on incrementing i = 1
on incrementing i = 2
on decrementing i = 1
on decrementing i = 0
Example:8

Here, x and y both are global variables. Since both of them have been defined outside all the functions both enjoy external storage class.

Note the difference between the following:
extern int y ;
int y = 31 ;

#include <stdio.h>
int x = 21;
int main()
{
    extern int y;
    printf("%d %d\n", x, y);
    return 0;
}
int y = 31;
Output:
21 31
Example:9
#include <stdio.h>
int x = 10;
void display();
void main()
{
    int x = 20;
    printf("\n%d", x);
    display();
}

void display()
{
    printf("\n%d", x);
}
Output:
20
10