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 24) 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. This section discusses two 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 an identifier 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.
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 variables x and y are local variables of automatic storage classthey exist only in the nearest enclosing pair of curly braces within the body of the function in which the definition appears:
auto double x, y;
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.8
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?
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. Today's optimizing compilers are capable of recognizing frequently used variables and can decide to place them in registers without needing a register declaration from the programmer.
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 will see in Section 6.10.
Identifiers with Static Storage Class
There are two types of identifiers with static storage classexternal 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.9
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.10
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:
static int count = 1;
All numeric variables of the static storage class are initialized to zero if they are not explicitly initialized by the programmer, 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. In Appendix E, C Legacy Code Topics, we discuss using extern and static with external identifiers and multiple-source-file programs.