Saturday, 5 October 2013

Variable storage classes in C


A variable in C can have any one of the four storage classes

1.       Automatic variables        (auto)

2.       External variables            (extern)

3.       Static variables                  (static)

4.       Register variables            (register)

 

Declaration of storage classesThe storage class is another qualifier (like long or unsigned) that can be added to a variable declaration as shown below:

auto int count;

register char ch;

static int x;

extern long total;

 

SN
Storage class
Where declared
Visibility
Lifetime
1.
None
Before all functions in a file (may be initialize)
Entire file plus other files where variable is declared with extern
Entire program (Global)
2.
extern
Before all functions in a file (cannot be initialized)
Entire file plus other files where variable is declared extern and the file where originally declared as global
Global
3.
static
Before all functions in a file
Only in that file
Global
4.
static
Inside a function
Only in that function
Global
5.
None or auto
Inside a function (or a block)
Only in that function or block
Until end of function of block
6.
register
Inside a function or block
Only in that function or block
Until end of function or block

 

1. Automatic Variable – Automatic variables are declared inside a function in which they are to be utilized. They are created when the function is called and destroyed automatically when the function is exited, hence the name automatic. Automatic variables are therefore private (or local) to the function in which they are declared. Because of this property, automatic variables are also referred to as local or internal variables.

 

ü  A variable declared inside a function without storage class specification is, by default automatic variable.

 

For instance, the storage class of the variable number in the example below is automatic.



main()
{   int number;
    ……
}





 

We may also use the keyword auto to declare automatic variables explicitly as:



    main()
    { 
        auto int number;
        …….
    }



 

2. External Variable In the C programming language, an external variable is a variable defined outside any function block. These variables are alive and active throughout the entire program. They are also known as global variables.

 

Also, as the extern extends the visibility to the whole program, by externing a variable we can use the variables anywhere in the program provided we know the declaration of them and the variable is defined somewhere.

File 1:

  int GlobalVariable;                 // implicit definition

  void SomeFunction(void);            // function prototype (declaration)

 

  int main()

  {

    GlobalVariable = 1;

    SomeFunction();

    return 0;

  }

File 2:

  extern int GlobalVariable;          // explicit declaration

 

  void SomeFunction(void)             // function header (definition)

  {           

    ++GlobalVariable;

  }

In this example, the variable GlobalVariable is defined in File 1. In order to utilize the same variable in File 2, it must be declared. Regardless of the number of files, a global variable is only defined once, however, it must be declared in any file outside of the one containing the definition.

If the program is in several source files, and a variable is defined in file1 and used in file2 and file3, then extern declarations are needed in file2 and file3 to connect the occurrences of the variable. The usual practice is to collect extern declarations of variables and functions in a separate file, historically called a header, that is included by #include at the front of each source file. The suffix .h

 

Although the variable y has been defined after both the functions, the external declaration of y inside the function informs the compiler that y is an integer type defined somewhere else in the program.

 

The extern declaration does not allocate storage space for variable.

 

Now let us try to understand extern with examples.

Example 1:

int var;
int main(void)
{
   var = 10;
   return 0;
}

Analysis: This program is compiled successfully. Here var is defined (and declared implicitly) globally.

Example 2:

extern int var;
int main(void)
{
  return 0;
}

Analysis: This program is compiled successfully. Here var is declared only. Notice var is never used so no problems.

Example 3:

extern int var;
int main(void)
{
 var = 10;
 return 0;
}

Analysis: This program throws error in compilation. Because var is declared but not defined anywhere. Essentially, the var isn’t allocated any memory. And the program is trying to change the value to 10 of a variable that doesn’t exist at all.

Example 4:

#include "somefile.h"
extern int var;
int main(void)
{
 var = 10;
 return 0;
}

Analysis: Supposing that somefile.h has the definition of var. This program will be compiled successfully.

Example 5:

extern int var = 0;
int main(void)
{
 var = 10;
 return 0;
}

Analysis: Guess this program will work? Well, here comes another surprise from C standards. They say that..if a variable is only declared and an initializer is also provided with that declaration, then the memory for that variable will be allocated i.e. that variable will be considered as defined. Therefore, as per the C standard, this program will compile successfully and work.


In short, we can say:

1.       Declaration can be done any number of times but definition only once.

2.       “extern” keyword is used to extend the visibility of variables/functions().

3.       Since functions are visible throughout the program by default. The use of extern is not needed in function declaration/definition. Its use is redundant.

4.       When extern is used with a variable, it’s only declared not defined.

5.       As an exception, when an extern variable is declared with initialization, it is taken as definition of the variable as well.


 

Example:

/* This program clarifies the scope of external variables */

#include<stdio.h>

void next(void);

void next1(void);

 

int a1=1;       /* external variable: global scope */

                /* scope: main(), next(), next1() */

 

void main()

{

     printf("*** Scope of External Variable ***\n\n");

     a1=2;

     printf("a1=%d\n",a1); /* a1=2 */

 

     next();

     printf("a1=%d\n",a1); /* a1=2 */

 

     next1();

     printf("a1=%d\n",a1); /* a1=13 */

 

     getchar();

}

 

int b1=0;       /* external variable */

                /* scope: global to next(), next1() */

                /* main() cannot access b1 */

 

void next(void)

{

     char a1;        /* auto var: scope to next() */

                     /* next() cannot access external a1 */

     a1='a';         /* local auto var */

     b1=77;          /* external var */

     printf("a1=%c, b1=%d\n",a1,b1); /* a1=a, b1=77 */

}

 

void next1(void)

{

     float b1;       /* auto var: scope local to next1() */

                     /* next1() cannot access external b1 */

     b1=19.2f;       /* auto var */

     a1=13;          /* external var */

     printf("a1=%d, b1=%f\n",a1,b1); /* a1=13, b1=19.2 */

}

 



Executing the program produces the following sample session:

***Scope of External Variables***

a1 = 2

a1 = a, b1 = 77

a1 = 2

a1 = 13, b1 = 19.200001

a1 = 13

External variables may be initialized in declarations just as automatic variables; however, the initializers must be constant expressions. The initialization is done only once at compile time, i.e. when memory is allocated for the variables variables.

In general, it is a good programming practice to avoid use of external variables as they destroy the concept of a function as a ``black box''. The black box concept is essential to the development of a modular program with modules. With an external variable, any function in the program can access and alter the variable, thus making debugging more difficult as well. This is not to say that external variables should never be used. There may be occasions when the use of an external variable significantly simplifies the implementation of an algorithm. Suffice it to say that external variables should be used rarely and with caution.

 

3. Static VariableAs the name suggests, the value of static variables persists until the end of the program. A variable can be declared static using the keyword static like

static int x;

static float y;

A static variable may be either an internal type of and externally type, depending on the place of declaration.

 

 

 

 

An example of static local variable in C:

#include <stdio.h>

void func();    /* function prototype declaration */

 

void main()

{

     func(); // prints 0

     func(); // prints 1

     func(); // prints 2

     getchar();

}

 

void func()

{

     static int x = 0;    /*x is initialized only once across three

calls of func() */

     printf("%d\n", x);   /* outputs the value of x */

     x = x + 1;

}

 

Internal static variables are those which are declared inside a function. The scope of internal static variables extend upon the end of the function in which they are defined. Therefore, internal static variables are similar to auto variables, except that they remain in existence (alive) throughout the remainder of the program. Therefore, internal static variables can be used to retain values between function calls.

                An external static variable is declared outside of all functions and is available to all the functions in that program. The difference between a static external variable and a simple external variable is that the static external variable is available only within the file where it is defined while the simple external variable can be accessed by other files.

 

Impact on Scope of Static Variables


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
 
#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 : (Compilation steps in UNIX operating system)

$ 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 limited the scope of the variable ‘count’ in file static.c to the file itself.

 

4. Register Variable - We can tell the compiler that a variable should be kept in one of the machine’s registers, instead of keeping in the memory (where normal variables are stored). Since a register access is much faster than a memory access, keeping the frequently accessed variables (e.g. loop control variables) in the register will lead to faster execution of programs. This is done as follows:   

register int count;

 

Although, ANSI standard does not restrict its application to any particular data type, most compilers allow only int or char  variables to be placed in the register.

               

Since only a few variables can be placed in the register, it is important to carefully select the variables for this purpose. However, C will automatically convert register variables into non-register variables once the limit is reached.

No comments:

Post a Comment