Scope Rules

The portion of the program where an identifier can be used is known as its scope. For example, when we declare a local variable in a block, it can be referenced only in that block and in blocks nested within that block. This section discusses four scopes for an identifierfunction scope, file scope, block scope and function-prototype scope. Later we will see two other scopesclass scope (Chapter 9) and namespace scope (Chapter 24).

An identifier declared outside any function or class has file scope. Such an identifier is "known" in all functions from the point at which it is declared until the end of the file. Global variables, function definitions and function prototypes placed outside a function all have file scope.

Labels (identifiers followed by a colon such as start:) are the only identifiers with function scope. Labels can be used anywhere in the function in which they appear, but cannot be referenced outside the function body. Labels are used in goto statements (Appendix E). Labels are implementation details that functions hide from one another.

Identifiers declared inside a block have block scope. Block scope begins at the identifier's declaration and ends at the terminating right brace (}) of the block in which the identifier is declared. Local variables have block scope, as do function parameters, which are also local variables of the function. Any block can contain variable declarations. When blocks are nested and an identifier in an outer block has the same name as an identifier in an inner block, the identifier in the outer block is "hidden" until the inner block terminates. While executing in the inner block, the inner block sees the value of its own local identifier and not the value of the identically named identifier in the enclosing block. Local variables declared static still have block scope, even though they exist from the time the program begins execution. Storage duration does not affect the scope of an identifier.

The only identifiers with function prototype scope are those used in the parameter list of a function prototype. As mentioned previously, function prototypes do not require names in the parameter listonly types are required. Names appearing in the parameter list of a function prototype are ignored by the compiler. Identifiers used in a function prototype can be reused elsewhere in the program without ambiguity. In a single prototype, a particular identifier can be used only once.


Common Programming Error 6.12

Accidentally using the same name for an identifier in an inner block that is used for an identifier in an outer block, when in fact the programmer wants the identifier in the outer block to be active for the duration of the inner block, is normally a logic error.

Good Programming Practice 6.4

Avoid variable names that hide names in outer scopes. This can be accomplished by avoiding the use of duplicate identifiers in a program.

The program of Fig. 6.12 demonstrates scoping issues with global variables, automatic local variables and static local variables.

Figure 6.12. Scoping example.

(This item is displayed on pages 266 - 267 in the print version)

1 // Fig. 6.12: fig06_12.cpp 2 // A scoping example. 3 #include 4 using std::cout; 5 using std::endl; 6 7 void useLocal( void ); // function prototype 8 void useStaticLocal( void ); // function prototype 9 void useGlobal( void ); // function prototype 10 11 int x = 1; // global variable 12 13 int main() 14 { 15 int x = 5; // local variable to main 16 17 cout << "local x in main's outer scope is " << x << endl; 18 19 { // start new scope 20 int x = 7; // hides x in outer scope 21 22 cout << "local x in main's inner scope is " << x << endl; 23 } // end new scope 24 25 cout << "local x in main's outer scope is " << x << endl; 26 27 useLocal(); // useLocal has local x 28 useStaticLocal(); // useStaticLocal has static local x 29 useGlobal(); // useGlobal uses global x 30 useLocal(); // useLocal reinitializes its local x 31 useStaticLocal(); // static local x retains its prior value 32 useGlobal(); // global x also retains its value 33 34 cout << " local x in main is " << x << endl; 35 return 0; // indicates successful termination 36 } // end main 37 38 // useLocal reinitializes local variable x during each call 39 void useLocal( void ) 40 { 41 int x = 25; // initialized each time useLocal is called 42 43 cout << " local x is " << x << " on entering useLocal" << endl; 44 x++; 45 cout << "local x is " << x << " on exiting useLocal" << endl; 46 } // end function useLocal 47 48 // useStaticLocal initializes static local variable x only the 49 // first time the function is called; value of x is saved 50 // between calls to this function 51 void useStaticLocal( void ) 52 { 53 static int x = 50; // initialized first time useStaticLocal is called 54 55 cout << " local static x is " << x << " on entering useStaticLocal" 56 << endl; 57 x++; 58 cout << "local static x is " << x << " on exiting useStaticLocal" 59 << endl; 60 } // end function useStaticLocal 61 62 // useGlobal modifies global variable x during each call 63 void useGlobal( void ) 64 { 65 cout << " global x is " << x << " on entering useGlobal" << endl; 66 x *= 10; 67 cout << "global x is " << x << " on exiting useGlobal" << endl; 68 } // end function useGlobal  

local x in main's outer scope is 5 local x in main's inner scope is 7 local x in main's outer scope is 5 local x is 25 on entering useLocal local x is 26 on exiting useLocal local static x is 50 on entering useStaticLocal local static x is 51 on exiting useStaticLocal global x is 1 on entering useGlobal global x is 10 on exiting useGlobal local x is 25 on entering useLocal local x is 26 on exiting useLocal local static x is 51 on entering useStaticLocal local static x is 52 on exiting useStaticLocal global x is 10 on entering useGlobal global x is 100 on exiting useGlobal local x in main is 5  


Line 11 declares and initializes global variable x to 1. This global variable is hidden in any block (or function) that declares a variable named x. In main, line 15 declares a local variable x and initializes it to 5. Line 17 outputs this variable to show that the global x is hidden in main. Next, lines 1923 define a new block in main in which another local variable x is initialized to 7 (line 20). Line 22 outputs this variable to show that it hides x in the outer block of main. When the block exits, the variable x with value 7 is destroyed automatically. Next, line 25 outputs the local variable x in the outer block of main to show that it is no longer hidden.

To demonstrate other scopes, the program defines three functions, each of which takes no arguments and returns nothing. Function useLocal (lines 3946) declares automatic variable x (line 41) and initializes it to 25. When the program calls useLocal, the function prints the variable, increments it and prints it again before the function returns program control to its caller. Each time the program calls this function, the function recreates automatic variable x and reinitializes it to 25.

Function useStaticLocal (lines 5160) declares static variable x and initializes it to 50. Local variables declared as static retain their values even when they are out of scope (i.e., the function in which they are declared is not executing). When the program calls useStaticLocal, the function prints x, increments it and prints it again before the function returns program control to its caller. In the next call to this function, static local variable x contains the value 51. The initialization in line 53 occurs only oncethe first time useStaticLocal is called.

Function useGlobal (lines 6368) does not declare any variables. Therefore, when it refers to variable x, the global x (preceding main) is used. When the program calls useGlobal, the function prints the global variable x, multiplies it by 10 and prints again before the function returns program control to its caller. The next time the program calls useGlobal, the global variable has its modified value, 10. After executing functions useLocal, useStaticLocal and useGlobal twice each, the program prints the local variable x in main again to show that none of the function calls modified the value of x in main, because the functions all referred to variables in other scopes.

Категории