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.