C++ Reference Material
Storage Classes and Linkage
In the following discussion it is important to remember the One Definition Rule, which says that you cannot use the same name for the definition of two or more of the same kind of thing, within the same scope. This applies to names in general, not just to names of variables. And if you could use the same name for different kinds of things, within the same scope, why on earth would you?
The terms declaration and definition mean different things, and it is important not to confuse them. Unfortunately, what each one means varies somewhat depending on whether it is referring to a type, a function, or a variable (object). For example:
class MyClass;which simply states that "there is such a class" and its full definition will be "coming later" (either in the current file, at compile time, or from some other file at link time).
There are two storage classes in C++:
Until C++11, C++
had the two storage class specifiers auto and
register, both of which applied to this automatic storage
class. But for many years neither of these was used very often. The
reason auto
was essentially never used is that in those
situations in which it could be used to specify the automatic storage
class, that storage class was the default in any case. The reason the
register
storage class was not used is that it was only a
"suggestion" to the compiler that a variable should be stored in a
register (a suggestion that the compiler was free to ignore), and
modern compilers are generally smart enough to figure out on their own
that a variable should be stored in a register, independent of any
advice from the programmer. [The reason a variable would be stored in a
register is that register access is much faster than memory access, so
a variable that is being accessed many times might help to speed up a
program by being stored in a register rather than in memory.]
With C++11, the auto keyword has been removed as a
storage class specifier and has been given new semantics. [Now you
can use the auto
keyword as a variable type, provided
the variable has an initializer, and the compiler will infer the type
of the variable from the type of the initializing value.] And the
keyword register
has been deprecated.
However, the concept of an "auotmatic storage class" certainly remains, and variables having this storage class are the ones that come into existence during program execution when their declarative region is entered, and cease to exist when that region is exited. This is the default storage class for local variables in functions, and it also applies to all variables declared within any code segment enclosed in braces (within and if-statement, for example, or the loop control variable declared in a for-loop).
In this storage class, variables come into existence (at least conceptually) when the program begins to execute and remain in existence for the duration of the program's execution time. This is the default storage class for global variables, which have the extern specifier by default.
You can also apply the static specifier to a local variable in a function, which causes the value of that variable to be retained from one call of the function to the next.
The static qualifier applied to global entities is discussed in the following section.
Global variables and functions in the global namespace are assumed to have the extern specifier by default, and hence have external linkage. This means they can be seen and used ("linked to", if you like) by code in other files, by default. Thus the use of the extern qualifier for this purpose with global variables and functions or function prototypes is superfluous.
However, applying the extern qualifier explicitly to what would otherwise be a global variable definition without an initializer means that the definition of that variable is found either later in the current file, or in another file.
A global constant definition, on the other hand, has internal linkage by default, but can be given external linkage by applying the extern qualifier. Such a constant definition must contain an initializer, since a constant cannot be given a value after it has been defined. If you want that constant to be visible in another file, the constant must appear in an extern const declaration in that other file.
Applying the static specifier explicitly to a global variable or function gives it internal linkage. This means that the variable or function is not accessible from any other file and may therefore not be used by any function not defined in the current file. This use of the static specifier was deprecated in favor of placing such a variable in the unnamed namespace of the file to which its use is to be limited, although the wisdom of this deprecation has been long debated among many C++ programmers of note, and it is not agreed by all that this was a good idea.
Because C++ allows function overloading (the use of several functions with the same name, within the same scope, but having different numbers and/or types of parameters to distinguish between them), a C++ compiler will also need some way to distinguish these function names. So, behind the scenes, it uses a process called name mangling, or more politely, name decoration, to achieve this goal.
Thus a "mangled" name, in C++, is a C++ compiler-generated string containing the actual (undecorated) name, followed by additional text representing type information including parameter(s) and return value.
When the names in a program that require this kind of "mangling" have, in fact, been "mangled", the linker can correctly (and thus safely) resolve all references to overloaded functions, and thus provide type-safe linkage.
The C++ keyword static crops up in the discussion of a number of topics, and since this one keyword is used in a number of different contexts, with somewhat different meanings in each, we provide here a table showing the different contexts and what the keyword means in each.
Context | Meaning |
---|---|
Applied to a local variable inside a function. | The variable is "permanent", in the sense that it is initialized only once and retains its value from one function call to the next. It is like having a global variable with local scope. Without a static qualifier, any local variable in a function "comes and goes" with each invocation of the function. |
Applied to either a "free" function (i.e., a function that is not a member function of a class), or to a global variable defined outside the body of any function. |
The scope of the function, or the variable, is limited to the file
in which it is defined (and, as usual, extends from the point of
definition to the end of the file). Without a static
qualifier, any free function or global variable in a file has the
extern qualifier by default, making it visible from other
files in the compilation unit.
Special Note |
Applied to a member variable of a class. | There is only one such variable for the class, no matter how many objects of the class are created. In other words, it turns the member variable from an "instance variable" into a "class variable". [This use of the static keyword is the same as in Java.] |
Applied to a member function of a class. | The function may access only static members of the class. That is, it may not access any instance members (since there may not be any, if no objects of the class have been created). [This use of the static keyword is also the same as in Java.] |
Note that only variables can have the automatic storage class.
The static and extern specifiers affect only the scope, not the lifetime, of variables (or objects):
The extern specifier applied to an entity (variable or function, say) means essentially that the definition of that entity appears "later on in this file", or "in another file".
int i; //variable definition without initializer int j = 6; //variable definition with initializerIf we apply the extern qualifier explicitly to the definition of the variable i above, then it becomes "just" a declaration, and is no longer a definition since now no memory is being assigned to i:
extern int i;Instead, we are now saying that the definition of i will appear either later on in the current file, or in another file. On the other hand, applying the extern qualifier explicitly to the definition of j above is simply superfluous:
extern int j = 6;This is a definition of j, with initializer, and j is available in other files linked to the one containing it, whether the extern is there or not. We should note, however, that the extern declaration of i can also appear locally (inside a function, for example), but the extern definition of j can only appear globally.
static int i; //variable definition without initializer; limited to current file static int j = 6; //variable definition with initializer; limited to current file
const int K = 10; //definition of a constant K (with internal linkage) static const int K = 10; //same as aboveIf we apply the extern qualifier explicitly to the definition of the constant K above, then we give it "external linkage" and it becomes available in other files linked to the file in which its extern definition appears:
extern const int K = 10; //definition of a constant K (with external linkage)Those other files that wish to have access to K must have the following extern declaration:
extern const int K; //declaration of constant K (with external linkage)