当变量在程序的某个部分被声明时,它只有在程序的一定区域才能被访问。这个区域由标识符的作用域(scope)决定。标识符的作用域就是程序中该标识符可以被使用的区域。例如,函数的局部变量的作用域局限于该函数的函数体。这个规则意味着两点。首先,其他函数都无法通过这些变量的名字访问它们,因为这些变量在它们的作用域之外便不再有效。其次,只要分属不同的作用域,你可以给不同的变量起同一个名字。
编译器可以确认4种不同类型的作用域——文件作用域,函数作用域,代码块作用域和原型作用域。标识符声明的位置决定它的作用域。
1.代码块作用域
位于一对花括号之间的所有语句称之为一个代码块。任何在代码块开始位置声明的标识符都具有代码块作用域(block scope),表示它们可以被这个代码块中的所有语句访问。
声明在代码块的开始位置的标识符和函数定义的形式参数(注意是函数定义)都具有代码块作用域。
当代码块处于嵌套状态时,声明于内层代码块的标识符的作用域到达该代码块的尾部便告终。然而,如果内层代码块有一个标识符的名字与外层代码块的一个标识符同名,内层的那个标识符就将隐藏外层的标识符——外层的那个标识符无法在内层代码中通过名字访问。
注意:尽量避免在嵌套的代码块中出现相同的变量名。这会引起逻辑混乱,代码阅读也很吃力。
2.文件作用域
任何在所有的代码块之外的声明的标识符都具有文件作用域(file scope)。它表示这些标识符从它们的声明之外直到它所在的源文件结尾处都是可以访问的。在文件中定义的函数名也具有文件作用域,因为函数名本身并不属于任何代码块。应该指出,在头文件中编写并通过#include指令包含到其他文件中的声明就好像它们是直接写在那些文件中一样。它们的作用域并不局限于头文件的文件尾。
3.原型作用域
原型作用域(prototype scope)只适用于在函数原型中声明的参数名(注意是函数声明)。在原型中(与函数定义不同),参数的名字(参数类型必需)并非必需。但是,如果出现参数名,可以随意取个名字,不必与函数定义的形参名匹配,也不必与函数实际调用时所传递的实参匹配。原型作用域防止这些参数名与程序其他部分的名字冲突。事实上,唯一可能出现的冲突就是在同一个原型中不止一次地使用同一个名字。
4.函数作用域
最后一种作用域类型时函数作用域(function scope)。它只适用于语句标签,语句标签用于goto语句。基本上,函数作用域可以简化为一条规则——一个函数中的所有语句标签必须唯一。