Variable Types in C: Auto, Static, Register and External – A Brief Guide

Apart from the regular types that a variable may have, like int, float, char, et cetera, there are a set of other qualifiers which may be added onto this in order to give the variable scope of the variable, whether that is local or global. A variable may have only one of these additional qualifiers at once.

The first of these types is auto, and it isn’t terribly interesting. Indeed, the auto type is very rarely specified, as it is the default for any place where the declaration is legal, and invalid elsewhere. An auto variable has local variable scope, meaning that it is only “visible” or can only be accessed and changed within the function or block in which it is declared. An auto variable disappears when it goes out of scope, freeing the memory which it was declared with, and any subsequent declaration of the variable will likely take place in a different part of memory. The use of an auto variable can be illustrated:

int sum_consecutive(int lower_bound, int upper_bound)
{
    auto int i; /* Value unknown! Probably something crazy. */
    auto int sum = 0; /* Will disappear when function finishes! */
    for (i = lower_bound; i <= upper_bound; i++)
        sum += i;
    return sum;
}

Neither i nor sum exist until the function is called. Both variables will probably be filled with junk until they are defined. Both variables can only be called or changed within the function in which they were called. Finally, both variables will disappear once the function has ended, their places in memory freed for other data. These variables have no persistence in memory.

Most of the time, this will be the desired effect, which is why it is the default for anything where it is legal. Sometimes, though, you want a variable to persist throughout the running of the program. This is where the static type comes in. A static variable is declared once at the start of a program, and it doesn’t disappear once it goes out of scope, unlike an auto variable. This can be illustrated by this simple function, which does little of use, but which is sufficient for demonstrative purposes:

#include <stdio.h>
int times_called(void);
main()
{
    int i;
    for (i = 0; i < 10; i++)
    printf("times_called() has been called %d times\n",
            times_called());
}

int times_called(void)
{
    /* The variable is declared and defined once.
     * Subsequent uses of the function will skip the declaration line. */
    static int i = 0;
    ++i; /* Incrementing the variable */
    return i;
}

If an auto variable was used instead of a static variable in times_called(), the return value would simply be 1 every time the function was called. The use of the static variable allows the variable to be incremented and for the value to be remembered throughout the program. The use of a static variable allows the function to work correctly. In the words of Brian Kernighan and Dennis Ritchie (The C Programming Language, 2nd Edition, 1988), “[…] internal static variables provide private, permanent storage within a single function.”

A third type of variable resembles the auto variable declaration. This is the register type, and while today’s optimising compilers make it largely unnecessary, it has its uses with older compilers and certain embedded systems like elevator controllers and the like. The register specifier suggests to the compiler to place a variable into a register if possible, although the compiler is free to ignore this. The & reference operator cannot be used with variables which have been declared to be register variables, regardless of whether they are actually placed into a register.

The use of this specifier would seem to be most useful on RISC microprocessors with a lot of general-purpose registers, such as the SPARC, MIPS and Power architectures and less so on standard PCs with Intel processors. Feel free to ignore it for the purposes of your own programs; the compiler usually knows best.

The final type specifier to be covered is extern, but in order to understand how to use it, one must understand where it might be used. Sometimes, one doesn’t want a specific variable to be limited to one function, but instead be visible to all functions. This is where global variables come into play. A global variable can be “seen”, called and changed by all functions, and this can be illustrated here:

#include <stdio.h>

int i; /* Global variable, declared outside any function. */

void funct(void);

main()
{
    i = 0; /* i isn't declared in main(), but can still be changed */
    i++; /* Again, changing i by incrementing it */
    printf("The value of i is %d\n", i);
    funct();
    /* i will be different after funct() */
    printf("The value of i is %d\n", i);
}

void funct(void)
{
    i++; /* i isn't declared in funct() either. */
    i += 3;
}

Running this program, we get the following results:

The value of i is 1
The value of i is 5

Even though i isn’t declared in either function, it can be accessed and changed in both functions. Notice that we don’t have to do anything special to access the variable in either function. This is because of the place where i was declared, right at the top of the program and before any of the functions. If we changed the place where i was declared, as in the following program:

#include <stdio.h>

void funct(void);

main()
{
    i = 0; /* i can't be seen by main()! */
    i++; /* This is a syntax error, and the compiler will complain. */
    printf("The value of i is %d\n", i);
    funct();
    /* i will be different after funct() */
    printf("The value of i is %d\n", i);
}

int i; /* This comes after main() and is no longer in its scope! */

void funct(void)
{
    i++; /* i isn't declared in funct(), but can be changed. */
    i += 3;
}

we’ll get a compiler error. main() is trying to access a variable called i, which as far as it is concerned, doesn’t exist. However, by using the extern specifier, main() can find i and change it in the same way as it did in the first program illustrating external variables.

In order to do this, we change main() to look like this:

main()
{
    /* Declaring an external variable, which is somewhere in
     * global scope */
    extern int i;
    i = 0; /* i can be seen again! */
    i++;
    ...
}

At this point, you may be wondering why we would use extern at all when we can just place the variable at the top of the source file and have it accessible to any function that needs it. The answer is that most serious projects in C are made up of several source files – and as an exercise, you should find a simple, free, open-source program written in C, such as GNU Nano, and look at how the program is constructed. A variable declared in one source file doesn’t exist in another one, and therefore, extern specifiers are required if one wishes to use global variables declared in other source files.

Be careful with the use of external variables. It is noted early on by Kernighan and Ritchie that the use of external variables can be dangerous, because they are always there even when you don’t want them. They have a tendency to make programs fragile and monolithic, and to destroy the generality and modularity of functions, such that they can’t easily be reused in other programs. This is antithetic to the aim of C to create a degree of modularity in programming, and should be avoided if at all possible.

About these ads

3 Responses

  1. Thanks raka.. @ Simple Language,Point Oriented

  2. Reblogged this on Salma Say 's :.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: