作用域与static关键字
更新日期:
我自己也常常会搞不清static的用法,再次总结一下,主要摘抄了《c和指针》这本书相关章节。
作用域
编译器可以确定4种不同作用域:
文件作用域:
在所有代码块之外声明的标示符都具有文件作用域,作用域在源文件结尾处结束。函数作用域:
函数作用域也具有代码块作用域的属性。
注:函数形参的作用域开始于形参的声明处,位于函数外。如果在函数体内部声明了名字与形参相同的局部变量,将隐藏形参。代码块作用域:
花括号中间的语句称为一个代码块。原型作用域:
只适用于函数原型中声明的参数名,貌似并没有什么用,暂时不用理。函数声明中的参数名字不是必须,原型作用域只是为了保证参数名字不会和程序其他部分的名字冲突。
链接属性:
标示符的链接属性决定如何处理在不同文件中出现的标示符。
分类:external(外部)
、internal(内部)
、none(无)
外部(external):
不论声明多少次,位于几个源文件都表示同一个实体。内部(internal):
在同一文件内的所有声明都指同一实体,不同文件中多个声明分属不同的实体。无(none):
被当作单独的个体,标示符的多个声明会当作独立不同的实体,互不影响。
注:缺省情况下,在所有函数外部的标示符具有external链接属性。
存储类型:
指存储变量值的内存类型,变量的存储类型决定变量何时创建、何时销毁以及它的值将保持多久。
存储变量的的地方:普通内存
、运行时堆栈
、硬件寄存器
变量的存储类型取决于它的声明位置:
- 具有文件作用域的变量存储于
静态内存
中,被称为静态变量
。在程序运行前创建。 - 具有代码块作用域的变量存储于
堆栈
中,称为自动变量
或局部变量
。程序执行时创建。 - 关键字register可以用于
自动变量
的声明,提示应该存储于硬件寄存器
,但是编译器不一定会理睬register关键字。基本上不会用register。
注:
- 对于在代码块内部声明的变量,加上static关键字,可以使它的存储类型自动变为静态。
- 修改变量的存储类型不能改变该变量的作用域!!!
- 函数的形式参数不能声明为静态。
静态变量和自动变量(也称局部变量)的重要区别:
- 静态变量如果没有初始值将会初始化为0
- 自动变量因为在程序链接时无法判断自动变量的存储位置,所以,自动变量没有缺省的初始值,是不确定的。
- 静态变量只是在程序运行前初始化一次,但是自动变量每次都会初始化。
关键字static:
static在不同的环境下,有不同的意思。
在函数定义时,或用于代码块之外的变量声明时(即具有文件作用域属性),static关键字用于修改标示符的链接属性,将external改为internal。
注:标示符的存储类型和作用域不会改变。这种方式声明的变量或函数只能在声明它们的源文件中访问。在代码块内部的变量声明时,用于修改变量的存储类型,从自动变量修改为静态变量。
注:变量的链接属性和作用域不受影响。
在函数内部的变量加上static关键字后,在程序整个执行过程中都存在,只会被初始化一次,函数再次调用时不会再被初始化。
具有external链接属性的实体总是具有静态存储类型。
static只对缺省链接属性为external的声明才有改变链接属性的效果。
全局变量在程序开始执行前创建,并在程序整个执行过程中始终存在。