Static Duration, External Linkage

Variables with external linkage are often simply called external variables. They necessarily have static storage duration and file scope. External variables are defined outside, and hence external to, any function. For example, they could be declared above the main() function or in a header file. You can use an external variable in any function that follows the external variable’s definition in the file. Thus, external variables are also termed global variables, in contrast to automatic variables, which are local variables.

The One Definition Rule

On the one hand, an external variable has to be declared in each file that uses the variable. On the other hand, C++ has the “one definition rule” (also known as odr), which states that there can be only one definition of a variable. To satisfy these requirements, C++ has two kinds of variable declarations. One is the defining declaration or, simply, a definition. It causes storage for the variable to be allocated. The second is the referencing declaration or, simply, a declaration. It does not cause storage to be allocated because it refers to an existing variable.

A referencing declaration uses the keyword extern and does not provide initialization. Otherwise, a declaration is a definition and causes storage to be allocated:

double up;             // definition, up is 0
extern int blem;       // blem defined elsewhere
extern char gr = 'z';  // definition because initialized

If you use an external variable in several files, only one file can contain a definition for that variable (per the one definition rule). But every other file using the variable needs to declare that variable using the keyword extern:

// file01.cpp
extern int cats = 20;  // definition because of initialization
int dogs = 22;         // also a definition
int fleas;             // also a definition
...
// file02.cpp
// use cats and dogs from file01.cpp
extern int cats;       // not definitions because they use
extern int dogs;       // extern and have no initialization
...
// file98.cpp
// use cats, dogs, and fleas from file01.cpp
extern int cats;
extern int dogs;
extern int fleas;
...

In this case, all the files use the cats and dogs variables defined in file01.cpp. However, file02.cpp doesn’t re-declare the fleas variable, so it can’t access it. The extern in file01.cpp isn’t really needed because the effect is the same if it is omitted (also see Figure 9.4).

Figure 9.4. Defining declaration and referencing declaration.

Image

Note that the one definition rule doesn’t mean that there can be only one variable with a given name. For example, automatic variables sharing the same name but defined in different functions are separate variables, independent of one another, and each having its own address. Also as later examples show, a local variable can hide a global variable of the same name. However, although a program can have different variables of the same name, each version can have only one definition.

What if you define an external variable and then declare a variable by the same name inside a function? The second declaration is interpreted as a definition for an automatic variable. The automatic variable is the one that is in scope when the program executes that particular function. Listings 9.5 and 9.6, to be compiled together, illustrate using an external variable in two files and how an automatic variable hides a global variable of the same name. The program also shows how you can use the keyword extern to re-declare an external variable defined earlier and how you can use C++’s scope-resolution operator to access an otherwise hidden external variable.

Listing 9.5. external.cpp


// external.cpp -- external variables
// compile with support.cpp
#include <iostream>
using namespace std;
// external variable
double warming = 0.3;       // warming defined
// function prototypes
void update(double dt);
void local();

int main()                  // uses global variable
{
    cout << "Global warming is " << warming << " degrees. ";
    update(0.1);            // call function to change warming
    cout << "Global warming is " << warming << " degrees. ";
    local();                // call function with local warming
    cout << "Global warming is " << warming << " degrees. ";
    return 0;
}


Listing 9.6. support.cpp


// support.cpp -- use external variable
// compile with external.cpp
#include <iostream>
extern double warming;  // use warming from another file

// function prototypes
void update(double dt);
void local();

using std::cout;
void update(double dt)      // modifies global variable
{
    extern double warming;  // optional redeclaration
    warming += dt;          // uses global warming
    cout << "Updating global warming to " << warming;
    cout << " degrees. ";
}

void local()                // uses local variable
{
    double warming = 0.8;   // new variable hides external one

    cout << "Local warming = " << warming << " degrees. ";
        // Access global variable with the
        // scope resolution operator
    cout << "But global warming = " << ::warming;
    cout << " degrees. ";
}


Here is the output from the program:

Global warming is 0.3 degrees.
Updating global warming to 0.4 degrees.
Global warming is 0.4 degrees.
Local warming = 0.8 degrees.
But global warming = 0.4 degrees.
Global warming is 0.4 degrees.

Program Notes

The output of the program in Listings 9.5 and 9.6 illustrates that both main() and update() can access the external variable warming. Note that the change that update() makes to warming shows up in subsequent uses of the variable.

The definition for warming is in Listing 9.5:

double warming = 0.3;       // warming defined

Listing 9.6 uses extern to make the warming variable available to the functions in that file:

extern double warming;  // use warming from another file

As the comment indicates, this declaration says, “Use the warming variable defined externally elsewhere.”

In addition, the update() function re-declares the warming variable by using the keyword extern. This keyword means “Use the variable by this name previously defined externally.” Because that is what update() would do anyway if you omitted the entire declaration, this declaration is optional. It serves to document that the function is designed to use the external variable.

The local() function demonstrates that when you define a local variable that has the same name as a global variable, the local version hides the global version. The local() function, for example, uses the local definition of warming when it displays the value of warming.

C++ goes a step beyond C by offering the scope-resolution operator (::). When it is prefixed to the name of a variable, this operator means to use the global version of that variable. Thus, local() displays warming as 0.8, but it displays ::warming as 0.4. You’ll encounter this operator again in namespaces and classes. In terms of clarity and error-avoidance, it would have been better and safer to use ::warming in the update() function instead of using just warming and relying on scope rules.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.176.72