Storage Classes in C
Storage Class specifiers in C is one of the important topic of memory management in C. Every variable that we declare in a C program has its scope and lifetime. Storage class allows us to determine a variable's scope, visibility, and lifetime.
What is Storage Class in C?
Whenever we define a variable in the program we also define its data type and its storage class.
These two properties tell a lot about a variable; for example, data type tells about the size and the binary representation of a variable inside the memory.
unsigned int represents a positive number, whereas signed int represents both negative and positive numbers.
As for the Storage class, it defines the following attributes of a variable:
1. Scope (Visibility of a variable):
The scope of a variable says where the variable is accessible and where it is not in the program. The scope of a variable is determined at compile-time only without creating any function call stack in which it is created, which happens at run-time. In simple words, when using a variable out of its scope, the compiler will throw an error.
2. Default definition value:
Memory allocation does not happen in the declaration, whereas memory gets allocated to the variable in the definition.
In definition, we allocate memory according to the variable data type, and if the programmer does not explicitly initialize it, it gets initialized to some default value according to the storage class.
The default definition value of a variable depends upon its storage class. It could be a random value or zero, depending on the storage class.
3. Lifetime:
The lifetime of a variable refers to its validity, that is, how long we can access it in the program within its permitted scope.
Syntax
The following syntax is to be followed to specify the storage class for a variable:
Memory Layout of a C program
A typical architecture of memory of a C program can be broken down into 4 sections:
1. Code Segment:
This consists of executable instructions of the program and is allocated a fixed size according to the length of instructions during the program's compilation. For example, a simple code for printing "Hello world" is stored inside the code segment.
2. Static & global variables:
As the name suggests, this section stores all the static and global variables created by the programmer in the entire program and allocates fixed memory during compile time according to the data type and the number of variables in the program.
3. Stack:
This stores activation records(i.e., a function call stack) of functions at the program's run time; thus, it grows dynamically according to the number of function calls made by the user.
4. Heap:
At first, it has nothing to do with the heap data structure. This is the program's free pool of memory, which is used at run time according to the user's memory needs, which is referred to as dynamic memory allocation in technical terms.
Summary of Storage Classes in C
Let us now go Summarize the Storage Classes in C:
Storage Class | Scope | Lifetime | Initial Value | Storage Location |
---|---|---|---|---|
Auto | Within the block, in which it is declared. | Within the block, in which it is declared. | Initialized with garbage value. | RAM |
Register | Within the block, in which it is defined. | Same as auto, within the block in which it is declared. | Initialized with garbage value. | Register |
Static | Within the block, in which it is defined. | Throughout the main program. | Zero. | RAM |
Extern | Global scope, unbound by any function. | Same as static, till the end of the main program. | Zero. | RAM |
Uses of C Storage Class
Let's look at the Uses of The C Storage Class:
- Helps to determine the scope, visibility, lifetime of a variable.
- We can use more than one variable with the same name.
Types of Storage Class in C
1. Automatic Storage class in C:
Objects of the auto-storage class are initialized with random(garbage) values by default. Auto is the default storage class for variables defined inside a function or a block. These variables are also called local variables. As the name suggests, ‘local,’ variables defined with auto are accessible within the function boundary or the block in which they are defined.
Syntax to define an auto variable:
All auto variables must be defined inside a block or function body. If you declare an auto variable with global scope( which can be accessed everywhere in the program), compilation will throw an error.
Here, min is an auto variable defined inside the main body with a garbage value during the program's runtime. As the main function ends, its activation record will be removed from the stack, freeing up all memory allocated to the variables.
Auto variables are allocated memory at the program's runtime in the activation record of the function in which they are defined inside the stack.
2. Register Storage Class in C:
Variable with register storage has all attributes similar to that of auto storage, which are:
- Local scope
- Random initial value(garbage value)
- Lifetime till the end of the block
The main difference is that variables of register storage are initialized inside a CPU register. Register variables come in handy if you want to access a variable frequently in the program; it cuts down the time required in memory access and results in faster access of the variable stored in the register.
Initializing variables with register storage is just a suggestion to the compiler, by the user that to store the variable in the register. It depends on various parameters such as compiler code optimisation techniques or registers' availability to decide whether to allocate register or not. If the register is not used the variable is stored in the main memory as in auto variable.
Syntax for register variable definition:
Compilers are smart enough to detect whether a variable needs a register or not. Registers are costly and are rarely available for simple programs.
3. Static Storage Class in C:
Static variables are initialized inside static memory during the program's compile time and are independent of the function call stack in which they are defined, which makes them alive even after the function’s activation record is destroyed.
Once a static variable is defined it lives until the end of the program.
Static variables in C are initialized with ‘0’ by default and their scope is limited within the parent block which are local static variables.
You can create global static variables by defining them at the start of the program which can be accessed anywhere in the program.
Output:
Here out is a global static variable with default value 0 and in is a local static variable with its scope limited to the main function only but lifetime is till the end of the program which is common to both global and local static.
Static variables preserve the values they are assigned throughout the program. Once a static variable is defined the compiler ignores the definition statement if it sees again.
Output:
In the above code, sVar is a local static variable and is initialized with zero in the static memory as the inc_static function is called the first time in the main function.
In the second call, the value of sVar is preserved and its definition statement is ignored since the variable sVar is already initialized in the first call. Leaving the definition statement the rest of the code is implemented as it is. Then the third call is made and is executed similarly to the second call.
4. External Storage Class in C and the extern keyword:
Global variables are initialized with an external storage class in the static memory. The syntax to define a global variable is:
Output:
Here gVar is a global variable initialized with ‘0’ by default and is available in the entire program and even to other files through the linker.
There is no reserved keyword for specifying a global variable. You just need to define a variable at the top of the program and that’s it.
Extern keyword:
The extern keyword is used to declare a global variable, we have learned above declaration vs definition, that in declaration memory does not get allocated to the variable we are declaring it is just a reference to the compiler that the variable definition is somewhere in the program or in another file.
In the above code, we have used extern to declare max variable in the main() which tells the compiler to use max without worrying about its definition which will get fixed at link-time from the same program or another. At run-time max can be used in the main function with the help of extern and its value will be changed to 5 and 5 will be printed on the screen.
If you remove the whole extern declaration statement extern in max; from the above code it’ll throw this compilation error, 'max' undeclared (first use in this function).
The program won’t get compiled since the compiler didn’t see any definition for max before its use. Hence, extern is used to declare global variables to successfully compile our program, and definitions will be linked at link time to the extern declarations.
The good practice is to define all external(global) variables at the beginning of the program and then omit all extern declarations within the same program.
Advantages and disadvantages of C Storage Class
Let's look at the advantages of The C Storage Class:
- Helps to determine the scope, visibility, and lifetime of a variable.
- We can use more than one variable with the same name.
Some disadvantages of The C Storage Class:
- We cannot use more than one storage class for a single variable.
- Changing the program to meet different needs becomes difficult, as we have to consider the variable's scope and lifetime.
Difference Between Auto and Static
Difference Points | Auto | Static |
---|---|---|
Declaration syntax | auto int a = 5; | static int a = 5; |
Scope | Inside block | Inside block |
Initial Value | Garbage | Zero |
Lifetime | Till the end of block | Till the end of the program |
Summary
To sum it up, storage classes play a crucial role in the memory management of a C program. From now on, make use of storage classes in C program and get hold of the memory of the program. Don’t let the compiler bully you :)
Storage class | Storage | Default Initial Value | Scope | Lifetime |
---|---|---|---|---|
Automatic | Stack | garbage | local within block | end of the block |
Register | Stack or CPU register | garbage | local within block | end of the block |
Static | Static memory | 0 | Local or global, within a block or within the file | End of the program |
External | Static memory | 0 | Global | End of the program |
It must be kept in mind that global and static variables are kept in static memory and local variables in the stack frame of function.
So the use of global and static variables should be as minimal as possible, as they are alive until the program ends which eats up static memory throughout the life of the program right from the compile-time.