First Next Previous Last Glossary About

Scope and storage specifiers


The C++ block

//ex18.cc
#include <iostream>

int i = 99;        /* an external or global declaration */

void junk(void);

int main ()
{

  int i = 1, j = 1;     // these are available within this block 
                        // unless redefined in an enclosed block 

  cout << "main block i is " << i 
       << " and j is "       << j << endl;

  { /* this is an enclosed block,i is redefined, j isn't */
    /* it isn't a good idea to do this sort of thing     */

   int i = 2;
   j = i << 4;

   cout << "second block i is " << i 
        << " and j is "         << j << endl;

  } /* end of enclosed block */

  cout << "main block i is " << i 
       << " and j is "       << j << endl;

  junk();

  return 0;

} /* this is the end of the main block */

void junk(void)
{ cout << "which i is this? " << i << endl; 
} /* another block */

In C++ a block is a set of statements enclosed in braces {block} or the code contained within a file. In the example here the total program is a block and it encloses other blocks. For example the block for the main() function starts with it's opening brace and finishes with that block's closing brace.

An identifier is available within a block unless it is redefined in an enclosed block.



Return to top of page

Scope defined.

//exscope1.cc
#include <iostream>
void show_x();

void main()
{ int x = 20;
  show_x();
}

void show_x()
{ cout << x; }

The scope of a name (an identifier) is the part of the program over which the name is defined. In others words it is that part of a program over which the identifier can be seen by other identifiers and used by other identifiers. For example:

If you compile exscope1.cc you will get an error:

exscope1.cc: In function `void show_x()': exscope1.cc:11: `x' undeclared (first use this function) exscope1.cc:11: (Each undeclared identifier is reported only once exscope1.cc:11: for each function it appears in.)

The reason for the error is that variables declared within a function are private or local to that function. The variable x declared in function main() is local to main. It is a private variable and function show_x() simply can't see it.



//exscope2.cc
#include <iostream>
void show_x();
int x = 20;

void main()
{
  cout << x;
  show_x();
}

void show_x()
{ cout << x; }

If the variable x is moved to a global position then it is available to other functions. Now, since x is outside any of the functions it is visible to everything.



//exscope3.cc
#include <iostream>
void show_x();
int x = 20; //global x

void main()
{ int x = 10;  //local x
  cout << x;
  show_x();
}

void show_x()
{ cout << x; }

An identifier can be made "invisible" by another identifier of the same name declared at a lower level in the program. In this example you can see that the global x is "replaced" by the local x in main() but not in show_x(). The x referred to by main() is the local x. The x referred to by show_x() is the global x.



//exscope4.cc
#include <iostream>
void show_x();

void main()
{ cout << x;
  show_x();
}

int x = 20; //this is a global
            //but is only available
            //from this point on. 

void show_x()
{ cout << x; }

There is another aspect to scope that you should be aware of. The position of an identifier within a block is also a factor in determining scope. If you compile this program you will get the error message exscope4.cc:6: `x' undeclared (first use this function) or something like it. The reference to x in main() is a reference to a variable that cannot be seen. This is because x, even though it is declared at a global level, is not declared until after main().

With regards to scope the question to ask is "Can the user of the identifier see the identifier?".



int fred()
{ int x, y;
}

In the function fred the variables x and y are local or private variables, they can't be accessed by another function since they won't be visible to another function. Usually local variables only exist during the execution of the function and each time the function is called the variables will need to be initialised before use. Variables like this are known as automatic variables. You normally don't declare local variables as automatic since they are "automatically" automatic.

Variables can be declared as global variables, available to everything, these are also known as external variables. External variables are defined outside of any functions and retain their values during the course of a program. If a function uses an external variable and the external variable is declared in the same source file as the function using it and before the function then no further declaration is required. But, if the external variable is declared in a different source file then any function which uses it must also declare the variable, as an external variable, e.g.

file1.cc
 int ext_x;  // declare the variable
 
file2.cc
#include <iostream>
#include "file1.cc"
void func_x()
{ extern int ext_x; // declare variable 
                    // so that the function 
                    // knows that it is
                    // external to the
                    // block

  ext_x = 21;
  cout << "In function func_x() "
       << ext_x 
       << endl;
}
file3.cc
#include "file2.cc"
  
 int main()
 { extern int ext_x;

   func_x();       
   cout << "In function main() "
        << ext_x 
        << endl;
   return 0;
 }

Even though the external variable ext_x is declared three times it only has memory allocated to it once.

Automatic and external variables are both storage specifiers. A third specifier is the static specification.

Return to top of page

External variables - static and automatic

//ex19.cc
#include <iostream>

// All of these (ext1, ext2, ext3, addupstatic, adduptstat2,
// addupauto) are external or global or (sometimes called) 
// public symbols.

int ext1 = 10, ext2 = 12;       
int ext3(void);
int addupstatic(void);
int addupstat2(void);
int addupauto(void);

int main ()
{ int x = 1,y = 2;  // these are local or automatic variables

  cout << "\nexternal auto " << ext1 << " "
       << ext2 << " "  << x << " " << y << endl;

  cout << "function with external " <<  ext3() << endl;

  cout << "static variables 1 ->";
  for (x = 0; x < 10; x++) cout << " " << addupstatic();
  cout << endl;

  cout << "static variables 2 ->";
  for (x = 0; x < 10; x++) cout << " " << addupstat2();
  cout << endl;

  cout << "auto variables     ->";
  for (x = 0; x < 10; x++) cout << " " << addupauto();
  cout << endl;

  return 0;
}

int ext3(void) { return ext1 * ext2; }

int addupstatic(void) // static vars are initialised at start up
{ static int x,y;     // and retain their values. 
 
 x += 1;  y += 1;  return x + y;
}

int addupauto(void) // auto vars are not initialised at startup
{ int x = 1, y = 1; // but each time they are called and do not
                    // retain their values.
 x += 1;  y += 1;  return x + y;
}

int addupstat2(void)      // static vars can be initialised to some
{ static int x = 4,y = 4; // value other than 0 but will only be
                          // initialised at the first call.
 x += 1;  y += 1; return x + y;
}
  1. Variables declared within a function are only accessible within the function. The scope or visibility of a variable determines whether it can be accessed from other functions in the same source file or in other source files. External variables are defined outside any block and memory for these is allocated once.
  2. Static variables are variables which are local to a function but which (unlike auto variables) retain their values between invocations of the function - these are internal static variables. The second kind of static are external or global variables that are local to a file but not a part of any function. The main use of these is to hide the variable so that other source code files don't see the variable. The latter kind may not make much sense to you at the moment but will when you start to build programs which are built from many different source files.

Example 19 shows the different kinds of storage specifications. You should study this example closely.

I mentioned earlier that an automatic variable inside a function doesn't exist until the function is called. At that time the memory for the automatic variable is allocated dynamically from a memory stack and released when the function is finished. Static storage comes from a different memory allocation - it is allocated from a static area of memory so static variables within functions can retain their values between calls to the functions.



Return to top of page


Tutorial

There isn't much to do as a tutorial for this topic apart from compiling and running the sample programs. Although storage specification is an important topic it is perhaps a bit early to look at it in any significant detail.


First Next Previous Last Glossary About


Copyright © 1999 - 2001 David Beech