当前位置: 首页 > 文档资料 > C++大学教程 >

3.11 作用域规则

优质
小牛编辑
113浏览
2023-12-01

程序中一个标识符有意义的部分称为其作用域。例如,块中声明局部变量时,其只能在这个块或这个块嵌套的块中引用。一个标识符的4个作用域是函数范围(function scope)、文件范围(filescope)、块范围(block scope)和函数原型范围(function-prototype scope)。后面还要介绍第五个——类范围(class scope)。

任何函数之外声明的标识符取文件范围。这种标识符可以从声明处起到文件末尾的任何函数中访问。全局变量、任何函数之外声明的函数定义和函数原型都取文件范围。

标号(后面带冒号的标识符,如start:)是惟一具有函数范围的标识符。标号可以在所在函数中任何地方使用,但不能在函数体之外引用。标号用于switch结构中(如case标号)和goto语句中(见第18章)。标号是函数内部的实现细节,这种信息隐藏(infomation hiding)是良好软件工程的基本原则之一。

块中声明的标识符的作用域为块范围。块范围从标识符声明开始,到右花括号(})处结束。函数开头声明的局部变量的作用域为块范围,函数参数也是,它们也是函数的局部变量。任何块都可以包含变量声明。块嵌套时,如果外层块中的标识符与内层块中的标识符同名,则外层块中的标识符“隐藏”,直到内层块终止。在内层块中执行时,内层块中的标识符值是本块中定义的,而不是同名的外层标识符值。声明为static的局部变量尽管在函数执行时就已经存在.但该变量的作用域仍为块范围。存储时间不影响标识符的作用域。

只有函数原型参数表中使用的标识符才具有函数原型范围。前面曾介绍过,函数原型不要求参数表中使用的标识符名称,只要求类型。如果函数原型参数表中使用名称,则编译器忽略这些名称。
函数原型中使用的标识符可以在程序中的其他地方复用,不会产生歧义。

常见编程错误 3.20

如果在内层块和外层块中使用同名标识符,而程序员又希望在内层块中引用外层块中的标识符,这通常会产生逻辑错误,因为实际上使用的还是内层块中标识符的值。

编程技巧 3.10

避免隐藏外层块范围名称的变量名,因此要在程序中避免重复使用标识符。

下面的程序演示了全局变量、自动局部变量和 static 局部变量的作用域问题。

// Fig. 3.12:fig03 12.cpp
// A scoping example
#include <iostream.h>

void a(void);   // function prototype
void b(void);   // function prototype
void c void );  // function prototype

int x = 1; // global variable

int main()
{
  int x - 5; // local variable to main

  cout << "local x in outer scope of main is " << x << endl;

  { // start new scope
    int x = 7;
    cout << "local x in inner scope of main is " << x << endl;
  } // end new scope

  cout << "local x in outer scope of main is" << x << endl;

  a(); // a has automatic local x
  b(); // b has static local x
  c(); // c uses global x
  a(); // a reinitializes automatic local x
  b(); // static local x retains its previous value
  c(); // global x also retains its value

  cout << "local x in main is " << x << endl;

  return 0;
}

void a(void)
{
  int x = 25; //  initiallzed each time a is called

  cout << endl
       << "local x in a is " << x
       << " after entering a" << endl;
  ++x;
  cout << "local x in a is " << x
       << "before exiting a" << endl;
}

void b(void) static int x = 50; // Static initialization only
                                // first time b is called.
cout << endl
     << "local static x is " << x
     << -on entering b " << endl;
        ++x;
cout << "local static x is" << x
     << "on exiting b" << endl;
}

void c(void)
        cout
    << endl
    << "global x is " << x
    << "on entering c" << endl;
  x *= 10;
  cout << "global x is " << x << "on exiting c" << endl;
}

输出结果:

local x in outer scope Of main is 5
local x in inner scope Of main iS 7
local x in outer scope Of main is 5

local x in a  is 25  after entering a
local x in a  ls 26  before  exiting  a

local static  x  is  50  On  entering b
local static  x  is  51  On  exiting b

global x is 1  on  entering  c
global x is 10 on  exiting  c

local  x in a  is 25 after entering a
local  x in a  is 26 before exiting a

local  static  x  is  51  on  entering b
local  statzc  x  is  52  On  exiting b

global x  is  lO  On  entering  c
global x  is  100 On  exiting  c
local  x  in main  is  5

全局变量x声明并初始化为1。这个全局变量在任何声明x变量的块和函数中隐藏。在main函数中,局部变量x声明并初始化为5。打印这个变量,结果表示全局变量x在main函数中隐藏。然后在main函数中定义一个新块,将另一个局部变量x声明并初始化为7,打印这个变量,结果表示其隐藏main函数外层块中的x。数值为7的变量x在退出这个块时自动删除,并打印main函数外层块中的局部变量x,表示其不再隐藏。程序定义三个函数,都设有参数和返回值。

函数a定义自动变量x并将其初始化为25。调用a时,打印该变量,递增其值,并在退出函数之前再次打印该值。每次调用该函数时,自动变量x重新初值化为25。函数b声明static变量x并将其初始化为10。声明为static的局部变量在离开作用域时仍然保持其数值。调用b时,打印x,递增其值,并在退出函数之前再次打印该值。

下次调用这个函数时,static局部变量x包含数值51。函数c不声明任何变量,因此,函数c引用变量x时,使用全局变量x。调用函数c时,打印全局变量,将其乘以10,并在退出函数之前再次打印该值。下次调用函数c时,全局变量已变为10。最后,程序再次打印main函数中的局部变量x,结果表示所有函数调用都没有修改x的值,因为函数引用的都是其他范围中的变量。