6.10 Scope Rules

The portion of a 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 block scope and global namespace scope. Later we’ll see other scopes, including class scope in Chapter 9, and function scope, function-prototype scope and namespace scope in Chapter 23.

Block Scope

Identifiers declared inside a block have block scope, which begins at the identifier’s declaration and ends at the terminating right brace (}) of the enclosing block. Local variables have block scope, as do function parameters (even though they’re declared outside the block’s braces). 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 one in the outer block is “hidden” until the inner block terminates—the inner block “sees” its own local variable’s value and not that of the enclosing block’s identically named variable.

Common Programming Error 6.6

Accidentally using the same name for an identifier in an inner block that’s used for an identifier in an outer block, when in fact you want the identifier in the outer block to be active for the duration of the inner block, is typically a logic error.

 

Error-Prevention Tip 6.9

Avoid variable names in inner scopes that hide names in outer scopes. Most compilers will warn you about this issue.

Local variables also may be declared static. Such variables also have block scope, but unlike other local variables, a static local variable retains its value when the function returns to its caller. The next time the function is called, the static local variable contains the value it had when the function last completed execution. The following statement declares static local variable count and initializes to 1:


static unsigned int count{1};

All static local variables of numeric types are initialized to zero by default. The following statement declares static local variable count and initializes it to 0:


static unsigned int count;

Global Namespace Scope

An identifier declared outside any function or class has global namespace scope. Such an identifier is “known” in all functions from the point at which it’s declared until the end of the file. Function definitions, function prototypes placed outside a function, class definitions and global variables all have global namespace scope. Global variables are created by placing variable declarations outside any class or function definition. Such variables retain their values throughout a program’s execution.

Software Engineering Observation 6.5

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—except for truly global resources such as cin and cout, global variables should be avoided. In general, variables should be declared in the narrowest scope in which they need to be accessed.

 

Software Engineering Observation 6.6

Variables used only in a particular function should be declared as local variables in that function rather than as global variables.

Scope Demonstration

Figure 6.11 demonstrates scoping issues with global variables, local variables and static local variables. Line 10 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 13 displays the value of global variable x. 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 19–23 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 as well as the global x. 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’s no longer hidden.


Fig. 6.11 Scoping example.

Alternate View

 1   // Fig. 6.11: fig06_11.cpp
 2   // Scoping example.
 3   #include <iostream>
 4   using namespace std;
 5
 6   void useLocal(); // function prototype
 7   void useStaticLocal(); // function prototype
 8   void useGlobal(); // function prototype
 9
10   int x{1}; // global variable 
11
12   int main() {
13      cout << "global x in main is " << x << endl;
14
15      int x{5}; // local variable to main 
16
17      cout << "local x in main's outer scope is " << x << endl;
18
19      { // block starts a new scope                               
20         int x{7}; // hides both x in outer scope and global x    
21
22         cout << "local x in main's inner scope is " << x << endl;
23      }                                                           
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 prior value
33
34      cout << "
local x in main is " << x << endl;
35   }
36
37   // useLocal reinitializes local variable x during each call
38   void useLocal() {
39      int x{25}; // initialized each time useLocal is called 
40
41      cout << "
local x is " << x << " on entering useLocal" << endl;
42      ++x;
43      cout << "local x is " << x << " on exiting useLocal" << endl;
44   }
45
46   // useStaticLocal initializes static local variable x only the
47   // first time the function is called; value of x is saved
48   // between calls to this function
49   void useStaticLocal() {
50      static int x{50}; // initialized first time useStaticLocal is called 
51
52      cout << "
local static x is " << x << " on entering useStaticLocal"
53         << endl;
54      ++x;
55      cout << "local static x is " << x << " on exiting useStaticLocal"
56         << endl;
57   }
58
59   // useGlobal modifies global variable x during each call
60   void useGlobal() {
61      cout << "
global x is " << x << " on entering useGlobal" << endl;
62      x *= 10;
63      cout << "global x is " << x << " on exiting useGlobal" << endl;
64   }

global x in main is 1
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

To demonstrate other scopes, the program defines three functions, each of which takes no arguments and returns nothing. Function useLocal (lines 38–44) declares local variable x (line 39) 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 local variable x and reinitializes it to 25.

Function useStaticLocal (lines 49–57) declares static variable x and initializes it to 50. Local variables declared as static retain their values even when they’re out of scope (i.e., the function in which they’re 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 50 occurs only once—the first time useStaticLocal is called.

Function useGlobal (lines 60–64) does not declare any variables. Therefore, when it refers to variable x, the global x (line 10, preceding main) is used. When the program calls useGlobal, the function prints the global variable x, multiplies it by 10 and prints it again before the function returns 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.

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

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