版权归原作者所有,如有侵权,请联系我们

[科普中国]-标识符作用域

科学百科
原创
科学百科为用户提供权威科普内容,打造知识科普阵地
收藏

简介

在计算机中,标识符是程序中变量、类型、函数和标号的名称。标识符作用域是指标识符绑定的实体在一个程序中有效的部分或表示着一个标识符(identifier)的作用范围。一般而言,标识符不同,标识符作用域是不同的,同一个标识符在不同命名空间的作用域是不同的,因为一个标识符可在多个命名空间中定义,但它在不同命名空间中的含义是互不相干的。理解标识符作用域,对分析整个程序功能和对程序进行优化是十分重要的。

标识符标识符是一个字符序列,用来标识变量、函数、数据类型等。任何程序都离不开标识符,也就是说,不可能有没有标识符的C++程序。在程序2-1中,include、void、main、int、i、cin、cout等都是标识符。

标识符可以由大写字母、小写字母、下划线(_)和数字0~9组成,但必须是以大写字母、小写字母或下划线(_)开头。在C++语言程序中,大写字母和小写字母不能混用,比如Name和name就代表两个不同的标识符。

标识符的命名规则

  1. 所有标识符必须由一个字母(a~z或A~Z)或下划线(_)开头;
  2. 标识符的其它部分可以用字母、下划线或数字(0~9)组成;
  3. 大小写字母表示不同意义, 即代表不同的标识符,如前面的cout和Cout;
    在定义标识符时,虽然语法上允许用下划线开头,但是,我们最好避免定义用下划线开头的标识符,因为编译器常常定义一些下划线开头的标识符。
    C++没有限制一个标识符中字符的个数,但是,大多数的编译器都会有限制。不过,我们在定义标识符时,通常并不用担心标识符中字符数会不会超过编译器的限制,因为编译器限制的数字很大(例如255)。
    一个写得好的程序,标识符应该尽量有意义。 比如表示年可以用year,表示长度可以用length,表示累加和可以用sum等,这样的标识符本身就增加了程序的可读性,使程序更加清晰易懂。
    C++语言的标识符经常用在以下情况中:
  4. 标识对象或变量的名字
  5. 类、结构和联合的成员
  6. 函数或类的成员函数
  7. 自定义类型名
  8. 标识宏的名字
  9. 宏的参数1

作用域概述在电脑程序设计中,作用域(scope,或译作有效范围)是名字(name)与实体(entity)的绑定(binding)保持有效的那部分计算机程序。不同的编程语言可能有不同的作用域和名字解析。而同一语言内也可能存在多种作用域,随实体的类型变化而不同。作用域类别影响变量的绑定方式,根据语言使用静态作用域还是动态作用域变量的取值可能会有不同的结果。

包含标识符的宣告或定义;

包含语句和/或表达式,定义或部分关于可运行的算法;

嵌套嵌套或被嵌套嵌套。

名字空间是一种作用域,使用作用域的封装性质去逻辑上组群起关相的众识别子于单一识别子之下。因此,作用域可以影响这些内容的名字解析。

程序员常会缩进他们的源代码中的作用域,改善可读性。

静态作用域与动态作用域静态作用域又叫做词法作用域,采用词法作用域的变量叫词法变量。词法变量有一个在编译时静态确定的作用域。词法变量的作用域可以是一个函数或一段代码,该变量在这段代码区域内可见(visibility);在这段区域以外该变量不可见(或无法访问)。词法作用域里,取变量的值时,会检查函数定义时的文本环境,捕捉函数定义时对该变量的绑定。

大多数现在程序设计语言都是采用静态作用域规则,如C/C++、C#、Python、Java、JavaScript……

相反,采用动态作用域的变量叫做动态变量。只要程序正在执行定义了动态变量的代码段,那么在这段时间内,该变量一直存在;代码段执行结束,该变量便消失。这意味着如果有个函数f,里面调用了函数g,那么在执行g的时候,f里的所有局部变量都会被g访问到。而在静态作用域的情况下,g不能访问f的变量。动态作用域里,取变量的值时,会由内向外逐层检查函数的调用链,并打印第一次遇到的那个绑定的值。显然,最外层的绑定即是全局状态下的那个值。

采用动态作用域的语言有Pascal、Emacs Lisp、Common Lisp(兼有静态作用域)、Perl(兼有静态作用域)。C/C++是静态作用域语言,但在宏中用到的名字,也是动态作用域。

类型函数作用域函数作用域(function scope),只适用标签(label)的名字。标签名字可以在它所出现的函数中的任何位置被goto语句使用。也就是说,在函数内部,可以先通过goto语句使用一个标签名字,之后在该函数内部才有该标签名字的定义。

函数原型作用域函数原型作用域(function prototype scope)是指,函数原型中声明的名字只在该原型结束前可见,在原型结束处即为作用域结束之处。2例:

void foo(int a, float b, vector c);全局作用域全局命名空间作用域(global namespace scope),也称作全局作用域(global scope)是指编译单元的最外部的声明区域中声明的名字的作用域。3这些名字在程序的各个编译单元之间均可见。全局名字是链接器需要识别的名字。一般说来,全局名字对应的实体在程序中应仅有一份,而不同编译单元都可以通过同一名字绑定到该实体上。

典型的具有全局作用域的名字,包括:全局变量、全局函数等。

C++规定,可以通过::来限定一个名字为全局作用域中的名字。这也是“全局命名空间”称谓的来源。例如:

int i; //全局变量namespace ns{int i;}using namespace ns;::i=102; //给全局变量i赋值,而不是ns::i赋值。这行如果不用“::”,则编译错误: reference to 'i' is ambiguous|枚举作用域枚举作用域(enumeration scope)是指枚举类型的成员(enumerator)的名字的作用域,起自其声明之处,终至枚举定义结束之处。4

C语言规定,枚举类型的成员(enumerator)的可见范围被提升至该枚举类型所在的作用域内。这被认为有可能污染了外部的作用域。为此,C++11引入了枚举类(enum class)解决此问题。