# Storage Class in C (auto, register, static, extern)

This article is a Series on the C programming tutorial and carries the discussion on C language programming and its implementation. In our last tutorial, we have seen Variables in C programming. In this tutorial, we will discuss the storage classes in C language. It aims to provide easy and practical examples for understanding the C program.

## Storage classes in C Language Tutorial

Before moving ahead, let’s quickly understand the difference between the lifetime and the scope of a variable.

### Scope of variable

The scope of a variable in C refers to the region of a program where the variable can be accessed and used. In simple words, this is the visibility of the variable.

### Life of the variable

In C programming, the “life” of a variable refers to its duration or existence during the execution of a program. Variables in C have different lifetimes based on their scope and storage class.

## Scope of variables

In C language there are four types of Scope available.

 Scope Meaning File scope Starts at the beginning of the file (also called a translation unit) and ends at 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

In the C language, the lifetime and scope of a variable are defined by its Storage Classes in C.

The following are four types of Storage Classes in C.

### Auto

Features :

 Storage Memory Scope Local / Block Scope Lifetime Exists as long as Control remains in the block Default initial Value Garbage

The `auto` storage classes in C are the default storage class for all local variables.

```{
int mount;
auto int month;
}```

The example above defines two variables within the same storage class. By default, all the local variables are `auto`. ‘`auto`‘ can only be used within functions, i.e., local variables.

### Register

Features :

 Storage CPU Register Scope Local to the block Lifetime Local to the block in which the 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 guarantees that we have declared any variable as `register` and it would be stored in the CPU register! Why? The reason is that CPU registers are limited, and they may be busy doing some other task. In that case, that variable works as the default storage class in C i.e. automatic storage class.

Note: Any variable stored in the CPU register or not depends on the capacity of the microprocessor. For example, if the microprocessor has a 16-bit register then it 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 or double variable then you won’t get any error messages because the compiler treats it as the default storage class i.e. auto storage class.

All looping programs where a variable is frequently used, declare a variable as a register.

### Extern

Features :

 Storage Memory Scope Global / File Scope Lifetime 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 an 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 the extern specifier the variable cannot be initialized because with the extern specifier, the 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 the variable `x` is defined later than it has been used in `printf`. In this example, the `extern` specifier tells the compiler that the variable `x` has already been defined and it is declared here for the compiler’s information.

```#include <stdio.h>

extern int x;

int main()
{
printf("x: %d\n", x);
}

int x=10;```

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.

Mostly this `extern` keyword will be used when we want to share the global variable in two or more` .c` files.

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

### Static Variables

Features :

 Storage Memory Scope Block Scope Lifetime The value of the variable persists between different function calls Default initial Value Zero

Static variables affect both the lifetime and the scope.

static variables are those variables whose lifetime remains equal to the lifetime of the program like global variables. Any local or global variable can be made static depending on what the logic expects out of that variable. Let’s consider the following example :

```#include<stdio.h>

char** func_Str();

int main(void)
{
char **ptr = NULL;
ptr = func_Str();
printf("\n [%s] \n",*ptr);
return 0;
}

char** func_Str()
{
char *p = "Linux";
return &p;
}```

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()`’. Let’s look at the output :

```\$ ./static
[Linux]
\$```

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 local character pointer (`char *p`) in 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 other operations.

Let’s prove this observation. Look at the code below :

```#include<stdio.h>

char** func1_Str();
char** func2_Str();

int main(void)
{
char **ptr1 = NULL;
char **ptr2 = NULL;

ptr1 = func1_Str();
printf("\n [%s] \n",*ptr1);

ptr2 = func2_Str();
printf("\n [%s] \n",*ptr2);

printf("\n [%s] \n",*ptr1);

return 0;
}

char** func1_Str()
{
char *p = "Linux";
return &p;
}

char** func2_Str()
{
char *p = "Windows";
return &p;
}```

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 functions 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 toward the end of the `main()` function is done by again using the address returned by `func1_Str()` to print the string ‘Linux’.

Now, let’s see the output :

```\$ ./static
[Linux]
[Windows]
[Windows]```

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. It’s just the correct scenario that exposed the loophole in the code.

Let’s go a bit deeper to see what happened after the address of the local variable was returned. See the code below :

```#include<stdio.h>

char** func1_Str();
char** func2_Str();

int main(void)
{
char **ptr1 = NULL;
char **ptr2 = NULL;

ptr1 = func1_Str();
printf("\n [%s] :: func1_Str() address = [%p], its returned address is [%p]\n",*ptr1,(void*)func1_Str,(void*)ptr1);

ptr2 = func2_Str();
printf("\n [%s] [%p]\n",*ptr1,(void*)ptr1);

return 0;
}

char** func1_Str()
{
char *p = "Linux";
return &p;
}

char** func2_Str()
{
char *p = "Windows";
return &p;
}```

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 :

```\$ ./static
[Windows] [0x7fff705e9378]```

The above output makes it clear that once the lifetime of the local variable of the function ‘`func1_Str()`’ gets over then the 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 the root of the problem is the lifetime of the pointer variables. This is where the ‘`static`’ storage class comes to the rescue. As already discussed the static Storage classes make the lifetime of a variable equal to that of the program. So, let’s make the local pointer variables as `static` and then see the output :

```#include<stdio.h>

char** func1_Str();
char** func2_Str();

int main(void)
{
char **ptr1 = NULL;
char **ptr2 = NULL;

ptr1 = func1_Str();
printf("\n [%s] :: func1_Str() address = [%p], its returned address is [%p]\n",*ptr1,(void*)func1_Str,(void*)ptr1);

ptr2 = func2_Str();
printf("\n [%s] [%p]\n",*ptr1,(void*)ptr1);

return 0;
}

char** func1_Str()
{
static char *p = "Linux";
return &p;
}

char** func2_Str()
{
static char *p = "Windows";
return &p;
}```

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

```\$ ./static
[Linux] [0x601028]```

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

#### Impact on Scope

In the 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 the same name in some other file, then, in that case, one of the variables has to be made as `static`. The following example illustrates it :

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

static.c

```#include<stdio.h>

int count = 1;

int main(void)
{
printf("\n count = [%d]\n",count);
return 0;
}```

static_1.c

```#include<stdio.h>

int count = 4;

int func(void)
{
printf("\n count = [%d]\n",count);
return 0;
}```

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

```\$ gcc -Wall static.c static_1.c -o static
/tmp/ccwO66em.o:(.data+0x0): multiple definition of `count'
/tmp/ccGwx5t4.o:(.data+0x0): first defined here
collect2: ld returned 1 exit status
\$```

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

```#include<stdio.h>

static int count = 1;

int main(void)
{
printf("\n count = [%d]\n",count);
return 0;
}```

static_1.c

```#include<stdio.h>

int count = 4;

int func(void)
{
printf("\n count = [%d]\n",count);
return 0;
}```

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

```\$ gcc -Wall static.c static_1.c -o static
\$```

So, we see that no error is thrown this time because `static` has 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 a 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 the 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 the previous section, suppose we have two files :

static.c

```#include<stdio.h>

void func();

int main(void)
{
func();
return 0;
}

void funcNew()
{
printf("\n Hi, I am a normal function\n");
}```

static_1.c

```#include<stdio.h>

void funcNew();

int func(void)
{
funcNew();
return 0;
}```

If we compile and run the code above :

```\$ gcc -Wall static.c static_1.c -o static
\$ ./static
Hi, I am a normal function
\$```

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

```#include<stdio.h>

void funcNew();

int func(void)
{
funcNew();
return 0;
}

void funcNew()
{
printf("\n Hi, I am a normal function\n");
}```

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

```\$gcc -Wall static.c static_1.c -o static
/tmp/ccqI0jsP.o: In function `funcNew':
static_1.c:(.text+0x15): multiple definition of `funcNew'
/tmp/ccUO2XFS.o:static.c:(.text+0x15): first defined here
collect2: ld returned 1 exit status
\$```

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

static_1.c

```#include<stdio.h>

static void funcNew();

int func(void)
{
funcNew();
return 0;
}

static void funcNew()
{
printf("\n Hi, I am also a normal function\n");
}```

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

```\$ gcc -Wall static.c static_1.c -o static
\$ ./static
Hi, I am also a normal function
\$```

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`.

## Storage classes – Final Comparison

 Features Automatic Storage Class Register Storage Class Static Storage Class External Storage Class Keyword auto register static extern Initial value Garbage Garbage Zero Zero Storage Memory CPU register Memory Memory Scope scope limited, local to block scope limited, local to block scope limited, local to block Global Life limited to the life of the block, where it is defined limited to the life of the block, where it is defined The value of variable persists between different function calls Global, till the program execution Memory Location Stack Register memory Segment Segment

In our next tutorial, we will discuss the Functions in C programming.

You can also read the below tutorials.

Subscribe
Notify of This site uses Akismet to reduce spam. Learn how your comment data is processed.
{"ft_lang_label":"__label__en","ft_lang_prob":0.8246916,"math_prob":0.9226343,"size":16388,"snap":"2023-40-2023-50","text_gpt3_token_len":4033,"char_repetition_ratio":0.15618896,"word_repetition_ratio":0.17492712,"special_character_ratio":0.2593361,"punctuation_ratio":0.13316424,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.95235133,"pos_list":[0,1,2],"im_url_duplicate_count":[null,null,null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2023-12-02T01:14:14Z\",\"WARC-Record-ID\":\"<urn:uuid:84e22278-337d-42ac-b255-243c111373bf>\",\"Content-Length\":\"354747\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:9953c70b-07c4-4c29-8de3-2d0fb266c125>\",\"WARC-Concurrent-To\":\"<urn:uuid:e74c0da4-f510-42a7-bac8-ac44ece7d8ca>\",\"WARC-IP-Address\":\"172.67.187.110\",\"WARC-Target-URI\":\"https://embetronicx.com/tutorials/p_language/c/storage-class-in-c-language/\",\"WARC-Payload-Digest\":\"sha1:ZJD6TFJSTLBSMMI2LXBMMNLVWTHA67TO\",\"WARC-Block-Digest\":\"sha1:IHC3YRP4QA7V25IPBKOP46TOMUJFNVW4\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2023/CC-MAIN-2023-50/CC-MAIN-2023-50_segments_1700679100309.57_warc_CC-MAIN-20231202010506-20231202040506-00388.warc.gz\"}"}