我在静态/动态作用域上遇到了以下问题:
以下程序片段是用允许全局变量,并且不允许函数的嵌套声明。
global int i = 100, j = 5;
void P(x) {
int i = 10;
print(x + 10);
i = 200;
j = 20;
print (x);
}
main() {P(i + j);}
Q1.如果编程语言使用静态范围和按需调用参数传递机制,由上述程序打印的值
(A) 115、220(B)25、220(C)25、15(D)115、105
Q2.如果编程语言使用动态作用域并按名称调用参数传递机制,由上述程序打印的值
(A) 115、220(B)25、220(C)25、15(D)115、105
我的想法:
关于Q1:由于它是静态作用域,并且根据需要调用,x应该被替换为i+j。但这会导致局部名称冲突,因为已经有一个名为i的变量。因此它(全局i)可能会被重命名,比如说i1,然后调用将是:
first call: print(x+10) -> (i1 + j + 10) -> (100 + 5 + 10) -> 115
second call: print(x) -> print(i1 + j) -> 105 (Already evaluated - call by need)
关于Q2:在动态作用域中,首先在本地函数中搜索变量,然后在调用该本地函数的函数中搜索,然后在该函数的调用中搜索,依此类推,直到调用堆栈。
按名称呼叫:
print (i1 + j + 10) -> print (100 + 5 +10 ) -> 115
第二个电话是
print(x) -> print(i1 + j) -> (100 + 20) = 120 // Evaluate again - Call be name.
这个答案正确吗?(选项中不存在)我有什么东西不见了吗?(动态绑定可能是?)
Q1
OP的答案是正确的(D)。事实上,由于全局 下面是一个确实有区别的例子: 正如OP已经指出的,第一次评估 按名称调用通常用于宏语言。那么,为什么不使用有史以来最著名的宏语言:C预处理器呢? 编译、运行并查看:25220。 按名称调用只需简单的搜索和替换;在 换句话说,当 所以正确答案是B,对吧?嗯,差不多。。。正确答案取决于CCD_ 14的实现。假设 结果现在更改为15、20。 这可能是动态作用域不利于代码可维护性的最重要原因。函数i
在执行P
期间不会被修改,因此按需调用和值调用global int i = 100, j = 5;
void IncreaseTheGlobal() {
i = i + 1; // static scoping means this is the GLOBAL i!
print(i);
}
void P(x) {
int i = 10;
IncreaseTheGlobal(); // 101 (increased global i)
print(i); // 10 (local i)
print(x); // 106 (x is evaluated; picks up increased global i)
IncreaseTheGlobal(); // 102 (2nd time increased global i)
print(x); // 106 (x not re-evaluated; unaffected by 2nd increase)
}
main() {
print(i); // 100 (original global i)
P(i + j);
print(i); // 102 (new global i)
}
x
时,它获取全局i
在该特定时刻具有的任何值。在该初始评估之后,x
不再受全局i
的后续修改的影响。Q2
#include <stdio.h>
int i = 100, j = 5;
#define print(num) printf("%dn", num)
#define P(x) {
int i = 10;
print(x + 10);
i = 200;
j = 20;
print(x);
}
main() {
P(i + j);
}
P
的主体内,用i + j
替换每次出现的x
。int i = 10;
print(i + j + 10); // 10 + 5 + 10 = 25
i = 200;
j = 20;
print(i + j); // 200 + 20 = 220
x
被评估时,i + j
内的i
和j
只是获取范围内发生的任何事情的当前值。print
也执行按名称调用,和print
定义了自己的局部变量i
,那么这将极大地改变结果。试试这个:#define print(num) { int i = 0; printf("%dn", num); }
print
中的实现更改(即使是更改局部变量的名称这样微不足道的事情)也可能在更高级别上破坏函数。
在第二部分中,即按名称调用
线路i=200将更新本地i
现在,当调用print(x)时,它将被print(i+j)=>print(200+20)=>220 所取代
对于Q1:
int i = 10;
print(x + 10); // print (i + j + 10); prints 10 + 5 + 10 = 25; local i gets used here
i = 200;
j = 20;
print (x); // print (i + j); call by need ensures, no reevaluation and i + j is 15.
所以,答案是C-25,15