Storage Classes in C


In C programming, storage classes determine the lifetime, visibility, and scope of variables. There are four main storage classes in C:

  1. Automatic Storage Class
  2. Static Storage Class
  3. External Storage Class
  4. Register Storage Class

Automatic Storage Class

Automatic (auto): The default storage class for local variables declared within a function or a block is “auto.” Variables declared with “auto” come into existence when entering the block and get destroyed when exiting it. The explicit use of the keyword “auto” is rare since it represents the default behavior for local variables.

For instance:

void exampleFunction() {
    auto int localVar; 
     // "auto" is optional here (same as just "int localVar;")
    // Rest of the function code
}

In this example, we have a function called exampleFunction. Inside this function, we declare a local variable localVar. The “auto” keyword is optional here because it is the default storage class for local variables. The function creates the variable localVar when called and destroys it when it returns, limiting its lifetime to the scope of the function.


Static Storage Class

Static (static):  The “static” storage class behaves differently based on whether we use it with a local variable or a global variable.

  • With local variables: When you use “static” with a local variable, the variable keeps its value between function calls. It means the variable holds its value across function invocations. The variable is initialized only once and keeps its value throughout the program’s lifetime.

  • With global variables: When “static” is used with a global variable, it limits the scope of that variable to the file in which it is declared. This means the variable is not accessible from other files using extern. It effectively gives the variable internal linkage.

For instance:

void exampleFunction() {
    static int counter = 0;
    counter++;
    printf("Counter: %d\n", counter);
}

In this example, we have a function called exampleFunction. Inside the function, we have a static local variable counter
During the program’s execution, we initialize the variable “counter” only once, and it keeps its value across different calls to exampleFunction. Each time we call the function, the counter increments, and it maintains its value throughout the program’s lifetime.


External Storage Class

External (extern): The “extern” storage class is used to declare variables that are defined in other files.
When we declare a variable as “extern,” it indicates that the variable exists and has a type, but it belongs to another location. The file where we define it will handle the actual memory allocation for the variable.

For instance:

// File1.c
int globalVar; 
// This is a global variable defined in File1.c

// File2.c
extern int globalVar; 
/* This is just a declaration indicating that
globalVar is defined elsewhere.*/

In this example, we have two separate C files: File1.c and File2.c.
We defined a global variable called globalVar in File1.c
File2.c needs to use a global variable defined in another file. To inform the compiler about the variable’s existence elsewhere, we must specify its location.
That’s why we use the extern keyword to declare the globalVar in File2.c, telling the compiler that the actual definition of the variable is in File1.c.


Register Storage Class

Register (register): The “register” storage class suggests to the compiler that a variable should reside in a CPU register rather than RAM memory. Note that the “register” keyword is just a suggestion, and the compiler may or may not place the variable in a register, depending on its own optimizations.

For instance:

void exampleFunction() {
    register int x; 
/* Suggests that the variable x should be stored
   in a CPU register.*/

// Rest of the function code
}

In this example, we have a function called exampleFunction. Inside the function, we declare a variable x with the register keyword. This suggests to the compiler that it should try to store the variable x in a CPU register for faster access, rather than using RAM memory. However, it’s essential to note that the “register” keyword is just a hint to the compiler, and the compiler may or may not honor this suggestion depending on its optimization strategies and hardware constraints. Modern compilers often ignore the use of register since compilers can automatically optimize the storage of variables depending on their usage patterns.

Modern compilers mostly ignore the “register” keyword usage due to their advanced optimizations, and the effects of these storage classes may vary depending on the compiler and platform.