作用域(scope)或者可见性是指变量在程序内的可见和可引用的范围。
比如:
1、 全局变量在所有的文件都可见,那他的作用域就是所有文件;
2、 static定义的全局变量,只在定义它的源文件中可见,那他的作用域就是其所在的源文件;
3、 函数内部的局部变量,只在其函数范围内可见;
4、 有些变量,只在某一块代码段内可见(花括号括起来的一段代码);
void test_fun()
{
int test_i = 0;
test_i = 10;
if (test_i != 0)
{
int test_count = 15;
test_i = test_count;
}
test_i = test_count;//这里会编译出错,因为test_count只在if条件的花括号中有效。
}
下面大部分内容来自《代码大全》。
《代码大全》这本书介绍了攻击窗口的概念:介于同一个变量多个引用点之间的代码可成为攻击窗口,在这个窗口中新增代码,可能会不当的修改此变量。
一般而言,把对一个变量的引用局部化,即把引用点尽可能集中在一起总是一种很好的做法。主要的好处是提高程序的可读性和可维护性。如果变量的引用点都很集中,则阅读代码的时候,只要关注这一块代码就可以了,否则,阅读者的目光需要在代码中跳来跳去。
如何衡量变量引用的集中程度?《代码大全》提到了变量跨度的概念:对变量所有引用间相隔的代码行数。
void test_fun()
{
int test_i = 0;
int test_j = 0;
test_i = 10;//和第一次引用间隔1行代码
if (test_i != 0)//和第二次引用间隔0行代码
{
int test_count = 15;
test_i = test_count;//和第三次引用间隔1行代码
}
}
test_i的跨度总共是2。test_i的平均跨度是2/3。
变量的存活时间—— 一个变量存在期间所跨越的语句总数。也就是从第一次引用,到最后一次引用之间跨越代码的行数。
跨度表明变量引用的集中程度,存活时间表明变量经历的语句。
如上图所示,test_i存活时间是6条语句。
低存活时间的好处:
1、减小攻击窗口,不易出错。
2、使你对代码有更准确的认识(提高可读性)
3、减少初始化错误。
最后,一个明显的好处是便于程序重构,如果一个程序拆分为多个小的程序,短的存活时间更有价值。
用跨度和生存时间来考察全局变量,会发现全局变量跨度和生存时间都很长——这是避免使用全局变量的好的理由之一。
1、在循环开始之前再去初始化改循环里使用的循环变量,而不是在该循环所属的子程序的开始处初始化这些变量。
2、直到变量即将被使用时再为其赋值。把声明和定义放在使用之前。
3、把相关语句放在一起。减少变量的跨度和生存时间。
4、把相关的语句组提取成功单独的子程序。把一个长的子程序拆分为更小的、单独的子程序可以缩小变量的作用域。
5、开始时使用最严格的可见性,然后根据需要扩展变量的作用域。当对变量作用域犹豫不决时,应该倾向于选择该变量所能具有的最小的作用域:首先将变量限制于某个特定的循环,然后是局限于某个子程序,其次是类的private变量,protected变量,再其次对包()可见,最后不得已的情况下再把它作为全局变量。
关于对变量作用域的态度,取决于程序员如何看待“方便性”和“智力上的可管理性”。作用域越大,在写代码时越方便。但是写出的程序更难于理解、阅读、调试和维护。
1、 全局变量在所有的文件都可见,那他的作用域就是所有文件。
2、 static定义的全局变量,只在定义它的源文件中可见,那他的作用域就是其所在的源文件。
3、 函数内部的局部变量,只在其函数范围内可见。
4、 有些变量,只在某一块代码段内可见(花括号括起来的一段代码)。
5、 尽量使变量的引用局部化。
6、 尽量缩短变量的存活时间。
7、 尽量减少变量的作用域。
《代码大全》第10章《使用变量的一般事项》会教你如何更好的使用变量。