为了说明c++的声明顺序所导致的作用域问题,考虑如下代码
1 #include<iostream>
2 //#include <map>
3 //#include <string>
4 using namespace std;
5
6 int a;
7 void first()
8 {
9 a = 1;
10 }
11
12 void second()
13 {
14 int a = 7;
15 first();
16 cout << "second:" << a << endl;
17 }
18
19
20 int main()
21 {
22 a = 2;
23 int num;
24 cin >> num;
25 if (num > 0)
26 {
27 second();
28 }
29 else
30 {
31 first();
32 }
33 cout << a << endl;
34 return 0;
35 }
36
猜想一下上面的代码输出的结果是什么?main函数中输出的结果是1。不论你输入的num值是正数还是负数结果都是1。为什么会这样呢?这是因为c++采用的是静态作用域规则。第9行代码是关键所在。对于c++这种静态语言而言,第9行代码实际修改的是全局变量a的值。所以该程序的最终结果会是1。那么动态作用域规则的语言会输出什么样的结果呢?那就要根据所输入的num来决定了。
c++声明变量的作用就是引进名字符号,表明该变量的作用域,而定义则是给变量分配内存,并且绑定值的过程。对于调用子函数的过程,为了找到子函数中的变量的声明作用域,编译器采用了静态链接的方法。对于程序的执行流程,编译器会维护一个栈,栈中会存储与相应调用函数对应的帧。编译器通过栈和帧数据结构来维护程序执行所调用的函数层次流程。要找到一个子函数中的变量声明域实际上就是在栈中相应帧中寻找该变量的声明。寻找起点是当前活动帧,而当前活动帧又通过静态链接(相当于指针)与它的父帧相关联。但是考虑上面的程序,当输入num大于0时,应该是先调用second,然后调用first,而second中对变量a重新进行了声明,如果栈中维护的层次是函数调用的层次,则此时first中修改的变量a应该是second中声明的变量a才是,那么结果输出应该是2,但是事实并非如此。所以我认为栈中的静态链接所链接的不是函数调用的层次,而是声明的层次。考虑上面的程序,全局变量a和函数first的声明是在同一层次的,则如果要寻找a中变量的声明,应该首先查找a所在的那个模块所对应的帧(姑且认为是全局帧吧,看成有一个全局范围的函数与之对应),则这时找到的a的声明应该就是全局变量a。所以如果按照这种分析的话,那么程序的结果就是1了。
以上只是我的猜想,由于最近要忙于考试,没有时间查阅更多资料,且编译原理那块已经几乎忘得差不多了。如有错误请各位指正。