Previous | Table of Contents | Next |
An extra keyword, called the storage-class, can be added to a declaration (usually at the beginning) in order to control certain aspects of a variables scope, duration, and linkage. To illustrate the use of storage classes, we must first look at how scope, duration, and linkage work in the absence of storage classes.
The scope or visibility of a variables identifier is controlled by the placement of the variables declaration. Variables declared within a function (or more locally, within a block; see section 4) have local scope, and are visible only within that function (or block). Variables declared outside of any function, on the other hand, have some degree of global scope, and are potentially visible to many functions.
The duration or lifetime of a variable determines when storage for it is allocated and deallocated. By default, local variables have automatic duration. This means that they spring into existence when the function containing them is called and disappear when the function returns. Variables declared outside functions, however, have static duration: They are created when the program is first invoked, and persist until the program terminates.
The automatic allocation of local variables means that if a function is called recursively, each invocation is allocated its own copies of all local variables, which therefore do not conflict with each other. Because automatic variables disappear when the containing function returns, they do not retain their values from call to call.
Global variables (and functions) can be used in programs that are built from multiple source files. A global variable or function may be referenced, via an external declaration, from many places in potentially many source files, but it must have exactly one defining instance, in exactly one source file. The term linkage refers to the process of matching up the references to global variables and functions, wherever they may appear, with their unique definitions.
All of the preceding attributes of a declaration may be modified by means of the storage-class specifier. The first storage-class to discuss is static, which has two different uses. When used in a declaration of a variable outside any function (an otherwise global variable), it limits the scope of that variable to the source file in which it is declared, and prevents it from being accessed from other source files. By default, outside a function, a declaration like
int globalvar;
declares a truly global variable that can potentially be accessed from any source file. With the addition of the keyword static, however,
static int privatevar;
the declaration is of a variable that, though global to its source file and accessible to any function in that source file, is not accessible to any function in any other source file. Functions can also be declared with the storage-class static, with the same result: A static function becomes private to its containing source file.
The second use of the storage-class specifier static is in controlling the duration of local variables. Inside a function, as mentioned, a declaration is by default of a variable with local scope and automatic duration. With the addition of the keyword static, however, the variable achieves static duration, meaning that it does not come and go as the function is called and returns, and that it does not lose its value between invocations of the function. Instead, it is created just once, when the program begins execution, and lasts as long as the program does. (This also means that one copy of the variable is shared among any recursive invocations of the function. See section 3.5.3 for a realistic example.)
The storage-class specifier extern is used in distinguishing between defining instances and external declarations of global variables and functions. Roughly speaking, a declaration not containing the storage-class extern is a defining instance, and a declaration with the storage-class extern is an external declaration. Section 3.5.4 discusses these two forms of declarations in more detail.
So far, we have mentioned two storage-class specifiers, static and extern. There are five storage-class specifiers in all, summarized here:
If a declaration includes an explicit storage-class specifier, the type may be omitted, and defaults to int. Thus,
register r;
is a declaration of an int variable r, which should be placed in a machine register, and
extern a[];
is an external declaration of an array of ints. (The size is omitted because it is set, elsewhere, by the defining declaration of the array.)
Previous | Table of Contents | Next |