6.9. Storage Classes
The programs you have seen so far
use identifiers for variable names. The attributes of variables include name,
type, size and value. This chapter also uses identifiers as names for
user-defined functions. Actually, each identifier in a program has other
attributes, including storage class, scope
and linkage.
C++ provides five storage-class specifiers: auto, register, extern, mutable and static. This
section discusses storage-class specifiers auto, register,
extern and static. Storage-class specifier mutable
(discussed in detail in Chapter
22, Other Topics) is used exclusively with
classes.
Storage Class, Scope and
Linkage
An identifier's storage class
determines the period during which that identifier exists in memory. Some
identifiers exist briefly, some are repeatedly created and destroyed and others
exist for the entire execution of a program. First we discuss the storage
classes static and automatic.
An identifier's scope is where the
identifier can be referenced in a program. Some identifiers can be referenced
throughout a program; others can be referenced from only limited portions of a
program. Section
6.10 discusses the scope of identifiers.
An identifier's linkage determines
whether it is known only in the source file where it is declared or across
multiple files that are compiled, then linked together. An identifier's
storage-class specifier helps determine its storage class and linkage.
Storage Class Categories
The storage-class specifiers can
be split into two storage classes: automatic storage class and static storage
class. Keywords auto and register
are used to declare variables of the automatic storage class. Such variables are
created when program execution enters the block in which they are defined, they
exist while the block is active and they are destroyed when the program exits
the block.
Local Variables
Only local variables of a function
can be of automatic storage class. A function's local variables and parameters
normally are of automatic storage class. The storage class specifier
auto explicitly declares variables of
automatic storage class. For example, the following declaration indicates that
double variable x is a local
variable of automatic storage class—it exists only in the nearest enclosing pair
of curly braces within the body of the function in which the definition
appears:
Local variables are of automatic
storage class by default, so keyword auto rarely
is used. For the remainder of the text, we refer to variables of automatic
storage class simply as automatic variables.
Performance Tip 6.1
|
Automatic storage
is a means of conserving memory, because automatic storage class variables exist
in memory only when the block in which they are defined is
executing. |
Software Engineering Observation 6.6
|
Automatic storage is an example of the
principle of least privilege, which is fundamental to good software engineering.
In the context of an application, the principle states that code should be
granted only the amount of privilege and access that it needs to accomplish its
designated task, but no more. Why should we have variables stored in memory and
accessible when they are not
needed? |
Register Variables
Data in the machine-language version of a program is
normally loaded into registers for calculations and other processing.
Performance Tip 6.2
|
The storage-class specifier
register can be placed before an automatic
variable declaration to suggest that the compiler maintain the variable in one
of the computer's high-speed hardware registers rather than in memory. If
intensely used variables such as counters or totals are maintained in hardware
registers, the overhead of repeatedly loading the variables from memory into the
registers and storing the results back into memory is
eliminated. |
Common Programming Error 6.11
|
Using
multiple storage-class specifiers for an identifier is a syntax error. Only one
storage class specifier can be applied to an identifier. For example, if you
include register, do not also include
auto. |
The compiler might ignore
register declarations. For example, there might
not be a sufficient number of registers available for the compiler to use. The
following definition suggests that the integer variable counter be placed in one of the computer's registers; regardless of
whether the compiler does this, counter is initialized to 1:
register int counter = 1;
The register keyword can be used only with local
variables and function parameters.
Performance Tip 6.3
|
Often, register is unnecessary. Optimizing compilers can recognize
frequently used variables and may place them in registers without needing a
register
declaration. |
Static Storage Class
Keywords extern and static declare identifiers for variables of the static
storage class and for functions. Static-storage-class variables exist from the
point at which the program begins execution and last for the duration of the
program. A static-storage-class variable's storage is allocated when the program
begins execution. Such a variable is initialized once when its declaration is
encountered. For functions, the name of the function exists when the program
begins execution, just as for all other functions. However, even though the
variables and the function names exist from the start of program execution, this
does not mean that these identifiers can be used throughout the program. Storage
class and scope (where a name can be used) are separate issues, as we'll see in
Section
6.10.
Identifiers with Static Storage
Class
There are two types of identifiers
with static storage class—external identifiers (such as global variables and global function names) and
local variables declared with the storage-class specifier static. Global variables are created by placing variable
declarations outside any class or function definition. Global variables retain
their values throughout the execution of the program. Global variables and
global functions can be referenced by any function that follows their
declarations or definitions in the source file.
Software Engineering
Observation 6.7
|
Declaring a
variable as global rather than local allows unintended side effects to occur
when a function that does not need access to the variable accidentally or
maliciously modifies it. This is another example of the principle of least
privilege. In general, except for truly global resources such as cin
and cout, the use of global variables
should be avoided except in certain situations with unique performance
requirements. |
Software Engineering
Observation 6.8
|
Variables used only
in a particular function should be declared as local variables in that function
rather than as global
variables. |
Local variables declared with the keyword static are still known only in the function in which they are
declared, but, unlike automatic variables, static local variables retain their values when the
function returns to its caller. The next time the function is called, the
static local variables contain the values
they had when the function last completed execution. The following statement
declares local variable count to be static and to be
initialized to 1:
All numeric variables of the static
storage class are initialized to zero if you do not explicitly initialized them,
but it is nevertheless a good practice to explicitly initialize all
variables.
Storage-class specifiers extern
and static have special meaning when they are
applied explicitly to external identifiers such as global variables and global
function names.