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?

An Important Distinction: Declaration vs. Definition

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:

  1. In the context of a class type, what is in the .h specification file is generally referred to as the class definition (its implementation file will be a .cpp file), while a class declaration (also called a forward declaration) is a statement like
    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).
  2. A function prototype is a function declaration, while a function definition is the function header complete with function body. Once again, a function prototype says, in one sense, "there is such a function, and you will see its full definition either later in this file (at compile time), or in some other file (at link time)".
  3. It is the distinction between variable (or object) declaration and definition that seems to cause the most confusion, especially since in this case we also have the (different) concepts of initialization and assignment to keep in mind. And if that isn't enough, there are some differences between constants and variables, and between C++ and its C ancestor. But ... to keep it relatively simple, think of it this way:

Storage Classes

There are two storage classes in C++:

  1. The first is the automatic storage class.

    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).

  2. The second is the static storage class, which has the two specifiers static and extern.

    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.

Linkage

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.

Type-safe linkage and "name mangling"

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.

What are the different uses and meanings of the keyword static?

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
An anonymous namespace can also be used for the same purpose.

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.]

Some Points to Note

  1. Scope, linkage and storage class of functions
    Note that identifiers other than those used for variable names or objects may also have scope, linkage and storage class. For example, function names (as well as variable names) default to: Thus functions have external linkage, but an explicit extern qualifier is not required for either function prototypes or function definitions.

    Note that only variables can have the automatic storage class.

  2. Variable (or object) lifetime
    Note, too, that as a program runs, some variables exist only briefly (a local variable in a function called only once, for example), some are created and destroyed repeatedly (a local variable in a function called repeatedly, for example), and still others exist throughout the execution of a program (a static global or local variable, for example).

    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".

  3. Initialization of static and automatic variables
  4. Local variables and the extern qualifier
    Locally defined variables cannot have the extern storage class specifier applied to them (although locally declared variables can). Or, equivalently, locally defined variables can only have the auto, register or static storage class specifier applied. Don't be confused by this. An extern declaration statement simply says that, "a global variable already exists somewhere and can now be used here"; it does not cause the creation of a new variable. It is for this reason that initialization in a local extern declaration is a compile-time error.
  5. Constants and variables are not quite the same
    Be careful to distinguish between variables and constants: The one definition rule (any variable or object can be defined only once, though it may be declared any number of times) applies to such objects, just as it does to any other object.

Some Examples

  1. If i and j below are global variables, they have external linkage by default, meaning they are available for use in other files to which their own file is linked. Both are variable definitions, though you will also see them called declarations, since any definition is also a declaration, but not vice versa.
    int i;     //variable definition without initializer
    int j = 6; //variable definition with initializer
    
    If 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.
  2. Applying the keyword static to either of the first two definitions given in the previous item limits its usage to the file in which it is defined:
    static int i;     //variable definition without initializer; limited to current file
    static int j = 6; //variable definition with initializer; limited to current file
    
  3. If K below is a global constant, it has internal linkage by default (unlike global variables, which have external linkage by default), meaning it is only available for use in the file in which it is defined (and is therefore, in effect, static const):
    const int K = 10; //definition of a constant K (with internal linkage)
    static const int K = 10; //same as above
    
    If 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)