Storage Class

Today we will Discuss Storage Class in C Language.

Storage Class in C Language Tutorial

SCOPE AND STORAGE CLASSES

Before moving ahead, lets quickly understand the difference between life time and scope of a variable.

Scope of variable

In which function the value of the variable would be available.

Life of the variable

How long the variable would exists.

Scope of variables

In C language there are four types of Scope is available.

ScopeMeaning
 

File scope

Starts at the beginning of the file (also called a translation unit) and ends with the end of the file. It refers only to those identifiers that are declared outside of all functions. File scope
identifiers are visible throughout the entire file. Variables that have file scope are global.
 

Block scope

Begins with the opening { of a block and ends with its associated closing }. However, block scope also extends to function parameters in a function definition. That is, function
parameters are included in a function’s block scope. Variables with block scope are local to their block.

Function prototype scope

Identifiers declared in a function prototype. visible within the prototype.
 

Function scope

Begins with the opening { of a function and ends with its closing }. Function scope applies only to labels. A label is used as the target of a goto statement, and that label must be within
the same function as the goto.

Storage Classes

In C language, the life time and scope of a variable is defined by its storage class.

The following are four types of storage class available in C language.

  • Automatic (auto)
  • Register
  • External (extern)
  • Static

1. Auto 

Features :

Storage

Memory

Scope

Local / Block Scope

Life time

Exists as long as Control remains in the block

Default initial Value

Garbage

The auto storage class is the default storage class for all local variables.

 

The example above defines two variables within the same storage class. ‘auto’ can only be
used within functions, i.e., local variables.

2. Register

Features :

Storage

CPU Register

Scope

Local to the block

Life time

Local to the block in which variable is
declared

Default initial Value

Garbage

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.

There are no guaranties that we have declared any variable as register and it would be
stored in CPU register! Why? The reason is because CPU register are limited, and they may be
busy doing some other task. In this case that variable works as default storage class i.e. automatic storage class.

Note: Any variable stored in CPU register or not depend on capacity of microprocessor. For
example, if the microprocessor has 16-bit register then they cannot hold a float value or a double value, which require 4 and 8 bytes respectively. However, if you use the register storage class for float, double variable then you won’t get any error messages because compiler treat it as default storage class i.e. auto storage class.

All looping program where a variable are frequently used, declare variable as register.

3. Extern

Features :

Storage

Memory

Scope

Global / File Scope

Life time

As long as the program’s execution
doesn’t come to an end.

Default initial Value

Zero

The extern specifier gives the declared variable external storage class. The principal use of extern is to specify that a variable is declared with external linkage elsewhere in the program. To understand why this is important, it is necessary to understand the difference between a declaration and a definition. A declaration declares the name and type of a variable or function. A definition causes storage to be allocated for the variable or the body of the function to be defined. The same variable or function may have many declarations, but there can be only one definition for that variable or function.

When extern specifier is used with a variable declaration then no storage is allocated to that variable and it is assumed that the variable has already been defined elsewhere in the program. When we use extern specifier the variable cannot be initialized because with extern specifier variable is declared, not defined.

In the following sample C program if you remove extern int x; you will get an error “Undeclared identifier ‘x'” because variable x is defined later than it has been used in printf. In this example, the extern specifier tells the compiler that variablex has already been defined and it is declared here for compiler’s information.

 

Also, if you change the statement extern int x; to extern int x = 50; you will again get an error “Redefinition of ‘x'” because with extern specifier the variable cannot be initialized, if it is defined elsewhere. If not then extern declaration becomes a definition.

Note that extern can also be applied to a function declaration, but doing so is redundant because all function declarations are implicitly extern.

4. Static Variables

Features :

Storage

Memory

Scope

Block Scope

Life time

Value of the variable persists between different function calls

Default initial Value

Zero

Static variables affects both life time and scope.

1.Impact on Life Time

static variables are those variables whose life time remains equal to the life time of the program. Any local or global variable can be made static depending upon what the logic expects out of that variable. Lets consider the following example :

 

In the code above, the function ‘func_str()’ returns the address of the pointer ‘p’ to the calling function which uses it further to print the string ‘Linux’ to the user through ‘printf()’. Lets look at the output :

 

The output above is as expected. So, is everything fine here? Well, there is a hidden problem in the code. More specifically, its the return value of the function ‘func_Str()’. The value being returned is the address of the local pointer variable ‘p’. Since ‘p’ is local to the function so as soon as the function returns, the lifetime of this variable is over and hence its memory location becomes free for any further modifications.

Lets prove this observation. Look at the code below :

 

In the code above, now there are two functions ‘func1_Str()’ and ‘func2_Str()’. The logical problem remains the same here too. Each of these function returns the address of its local variable. In the main() function, the address returned by the func1_Str() is used to print the string ‘Linux’ (as pointed by its local pointer variable) and the address returned by the function func2_Str() is used to print the string ‘Windows’ (as pointed by its local pointer variable). An extra step towards the end of the main() function is done by again using the address returned by func1_Str() to print the string ‘Linux’.

Now, lets see the output :

 

The output above is not as per expectations. The third print should have been ‘Linux’ instead of ‘Windows’. Well, I’d rather say that the above output was expected. Its just the correct scenario that exposed the loophole in the code.

Lets go a bit more deep to see what happened after address of local variable was returned. See the code below :

 

The code is above is modified to print the address of the functions and the address of their respective local pointer variables. Here is the output :

 

The above output makes it clear that once the lifetime of the local variable of the function ‘func1_Str()’ gets over then same memory address is being used for the local pointer variable of the function ‘func2_Str()’ and hence the third print is ‘Windows’ and not ‘Linux’.

So, now we see what that the root of the problem is the life time of the pointer variables. This is where the ‘static’ storage class comes to rescue. As already discussed the static storage class makes the lifetime of a variable equal to that of the program. So, lets make the local pointer variables as static and then see the output :

 

Note that in code above, the pointers were made static. Here is the output :

So we see that after making the variables as static, the lifetime of the variables becomes equal to that of the program.

2. Impact on Scope

In case where code is spread over multiple files, the static storage type can be used to limit the scope of a variable to a particular file. For example, if we have a variable ‘count’ in one file and we want to have another variable with same name in some other file, then in that case one of the variable has to be made static. The following example illustrates it :

Here we use two files (static.c and static_1.c)

//static.c

 

// static_1.c

 

Now, when both the files are compiled and linked together to form a single executable, here is the error that is thrown by gcc :

 

So we see that gcc complains of multiple declarations of the variable ‘count’.

As a corrective measure, this time one of the ‘count’ variable is made static :

//static.c

 

// static_1.c

 

Now, if both the files are compiled and linked together :

 

So we see that no error is thrown this time because static limited the scope of the variable ‘count’ in file static.c to the file itself.

Static Functions

By default any function that is defined in a C file is extern. This means that the function can be used in any other source file of the same code/project (which gets compiled as separate translational unit). Now, if there is a situation where the access to a function is to be limited to the file in which it is defined or if a function with same name is desired in some other file of the same code/project then the functions in C can be made static.

Extending the same example that was used in previous section, suppose we have two files :

//static.c

 

// static_1.c

 

If we compile, link and run the code above :

 

So we see that the function funcNew() was defined in one file and successfully got called from the other. Now, if the file static_1.c wants to have its own funcNew(), ie :

// static_1.c

 

Now, if both the files are compiled and linked together :

 

So we see that the compiler complains of multiple definitions of the function funcNew(). So, we make the funcNew() in static_1.c as static :

// static_1.c

 

Now, if we compile, then we see that the compiler never complains :

 

Similarly, if static.c wants that its funcNew() should be accessible from within static.c only then in that case funcNew() in static.c can be made static.

Final Comparison 

FeaturesAutomatic Storage ClassRegister Storage ClassStatic Storage ClassExternal Storage Class
Keywordautoregisterstaticextern
Initial valueGarbageGarbageZeroZero
StorageMemoryCPU registerMemoryMemory
Scopescope limited, local to blockscope limited, local to blockscope limited, local to blockGlobal
Lifelimited life of block, where definedlimited life of block, where definedValue of variable persist between different function callsGlobal, till the program execution
Memory LocationStackRegister memorySegmentSegment

If you have any doubts just comment below. Thank you for reading 🙂  Click Here to read about Enum or Enumeration in c

Download our new Android app. You can learn all Embedded Tutorials from your Android Phone easily.

Click Here to Download App!