如果一个变量在某个文件或函数范围内是有效的,则称该文件或函数为该变量的作用域,在此作用域内可以引用该变量,所以又称变量在此作用域内“可见”,这种性质又称为变量的可见性,例如图4.16中变量a、b在函数f1中可见。
如果一个变量值在某一时刻是存在的,则认为这一时刻属于该变量的存储期,或称该变量在此时刻“存在”。书中表4.2表示各种类型变量的作用域和存在性的情况。
可以看到自动变量和寄存器变量在函数内的可见性和存在性是一致的。在函数外的可见性和存在性也是一致的。静态局部变量在函数外的可见性和存在性不一致。静态外部变量和外部变量的可见性和存在性是一致的。
(5) static声明使变量采用静态存储方式,但它对局部变量和全局变量所起的作用不同。对局部变量来说,static使变量由动态存储方式改变为静态存储方式。而对全局变量来说,它使变量局部化(局部于本文件),但仍为静态存储方式。从作用域角度看,凡有static声明的,其作用域都是局限的,或者局限于本函数内(静态局部变量),或者局限于本文件内(静态外部变量)。
4.14 关于变量的声明和定义
由第2章已经知道,一个函数一般由两部分组成: (1)声明部分; (2)执行语句。声明部分的作用是对有关的标识符(如变量、函数、结构体、共用体等)的属性进行说明。对于函数,声明和定义的区别是明显的,在本章4.4.3节中已说明,函数的声明是函数的原型,而函数的定义是函数功能的确立。对函数的声明是可以放在声明部分中的,而函数的定义显然不在函数的声明部分范围内,它是一个文件中的独立模块。
对变量而言,声明与定义的关系稍微复杂一些。在声明部分出现的变量有两种情况:一种是需要建立存储空间的(如int a; );另一种是不需要建立存储空间的(如extern int a;)。前者称为定义性声明(defining declaration),或简称为定义(definition)。后者称为引用性声明(referenceing declaration)。广义地说,声明包括定义,但并非所有的声明都是定义。对“int a;” 而言,它是定义性声明,既可说是声明,又可说是定义。而对“extern int a;” 而言,它是声明而不是定义。一般为了叙述方便,把建立存储空间的声明称为定义,而把不需要建立存储空间的声明称为声明。显然这里指的声明是狭义的,即非定义性声明。例如:
int main( )
{extern int a; //这是声明不是定义。声明a是一个已定义的外部变量
…
}
int a; //是定义,定义a为整型外部变量
外部变量定义和外部变量声明的含义是不同的。外部变量的定义只能有一次,它的位置在所有函数之外,而同一文件中的外部变量的声明可以有多次,它的位置可以在函数之内,也可以在函数之外。系统根据外部变量的定义分配存储单元。对外部变量的初始化只能在定义时进行,而不能在声明中进行。所谓声明,其作用是向编译系统发出一个信息,声明该变量是一个在后面定义的外部变量,仅仅是为了提前引用该变量而作的声明。extern只用作声明,而不用于定义。
用static来声明一个变量的作用有二: (1)对局部变量用static声明,使该变量在本函数调用结束后不释放,整个程序执行期间始终存在,使其存储期为程序的全过程。(2)全局变量用static声明,则该变量的作用域只限于本文件模块(即被声明的文件中)。
请注意,用auto,register,static声明变量时,是在定义变量的基础上加上这些关键字,而不能单独使用。如“static a;”是不合法的,应写成“static int a;”。
评论