C Storage Classes

In C, storage class determines the part of storage to allocate memory for a variable. It also determines the scope of a variable.

When we define a variable, it gets some physical location in memory where it's value is stored. Memory and CPU registers are two types of memory locations where a variable's value can be stored. Storage class decides where a variable is going to reside i.e. either in memory or in registers.

Storage Class Types

There are four storage classes in C those are automaticregisterstatic, and external.

These storage classes are specified with storage class specifier. They are:

  • auto
  • register
  • extern
  • static

These specifiers tell the compiler how to store the subsequent variable.

The general form of a variable declaration that uses a storage class is shown here:

storage_class_specifier data_type variable_name;

General rules to be considered while specifying the storage class for a variable are:

  1. At most one storage class specifier may be given to a variable.
  2. If no storage class specifier is specified then following rules are used:
  • Variables declared inside a function are taken to be auto.
  • Functions declared within a function are taken to be extern.
  • Variables and functions declared outside a function are taken to be static with external linkage. Variables and functions having external linkage are available to all files that constitute a program.
  • Variable and functions declared inside function and declared as static have internal linkage. These are known only within the file in which they are declared.

1. Automatic Storage Class

All variables defined within a function or block by default belong to an automatic storage class if no storage class is mentioned. Storage class specifier auto can be used to make a variable with automatic storage class. 

For a variable with automatic storage class, memory is allocated for it on the “stack”; this memory is managed automatically by the compiler.

If the variable is not explicitly initialised, then it will hold an undefined value ( also called Garbage value). It is often good practice to initialise a local variable when it is declared.

Variables having automatic storage class are local to the block which they are defined in, and get destroyed on exit from the block and are said to go "out-of-scope".

The following program helps to have clear about above explanation.

#include <stdio.h>
int main( )
{
  auto int num;
  { //level 2 scope
    int num = 20;
    {  //level 3 scope
      auto int num = 30;
      printf ( "Inside3 i = %d \n", num);
    }
    printf ( "Inside2 i = %d \n ", num);
  }
  printf( "Inside1 i = %d \n", num);
}

The output of the program is:

Inside3 i = 30 
Inside2 i = 20 
Inside1 i = 343334

Here, the value of i in Inside1 can be different in your case as it is garbage value ( because i is unassigned in main() function scope ). Also, even though num in Level 2 scope is unspecified, it is auto by default.

 

2. Static Storage Class

The keyword static is a storage class specifier.  Static variables can be used within function or file.

static keyword can be viewed as a qualifier as it imparts different properties depending on whether an object is a local variable, an external variable, or a function.

Local variables keep their local visibility but gain static extent. They are initialised to zero by default and retain their values between function calls.

The following program illustrates the point mentioned above.

#include<stdio.h>
int increment(void)
{
    static int local_static; /* local scope, static extent, initial value 0 */
    printf("local_static = %d \n ",local_static);
    return local_static++; /* 1st call will return: 0, 2nd: 1, 3rd: 2, ... */
}
int main()
{
    printf("first call : %d \n",increment());
    printf("second call : %d \n",increment());
    printf("third call : %d \n",increment());
}

The ouput of the program is:

local_static = 0
first call : 0
local_static = 1
second call : 1
local_static = 2
third call: 2

Here, local_static is initalized with 0 and its value is retained on each function call.

When external variables and functions that are qualified as static, they obtain file scope. This means their
visibility is limited to a single source file. Their names are not exported to the linker and are not
visible to object modules of other source files. This prevents unwanted access by code in other parts of the program and reduces the risk of naming conflicts.

The code snippet below explains this point:

File one.c:
    static double myvariable;
    static void myfunc(int idx);
File two.c:
    static int myvariable; /* no conflict with file one.c */
    static int myfunc(int idx); /* no conflict */

Here, declarations are unrelated and non-conflicting.

 

3. Register Storage Class

Register storage class variable is declared with the register specifier.

Variables belonging to register storage class are local to the block which they are defined in, and get destroyed on exit from the block i.e. they go "out-of-scope" at end of the block.

It is equivalent to auto declaration except that they are placed in CPU registers, not in memory as it will be accessed frequently.So, only a few variables are actually placed into registers, and only certain types are eligible; the restrictions are implementation-dependent.

Register variables are also given no initial value by the compiler.

The following code declares register variable.

#include <stdio.h>

int main()
{
  register int num = 20;

  printf("Value of num: %d \n", num);
}

 

4. External Storage Class

The extern specifier gives the declared variable external storage class.

Also, the extern keyword is used to declare the existence of an external variable in one file when it is defined in another. So, when we use extern specifier the variable cannot be initialized because with extern specifier variable is declared, not defined.

Function prototypes may also be preceded by extern, but this is not essential as they are external by default.

The following program is an example of external variables and functions shared across two source-files:

File first.c:
   int global_variable; /* external variable definition */
   extern double my_variable; /* external variable declaration (defined elsewhere) */
   void my_function(int idx); /* external function prototype (declaration) */

File second.c:
   double my_variable = 50.50; /* external variable definition */
   void my_function(int idx) /* Function definition */
   {
     extern int global_variable; /* external variable declaration */
     ...
   }

So, in first.c, if you print the value of my_variable, it will be 50.50

C Functions
C Scope and Lifetime