c-具有动态作用域的按名称调用



我在静态/动态作用域上遇到了以下问题:

以下程序片段是用允许全局变量,并且不允许函数的嵌套声明。

 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)。事实上,由于全局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)
}

正如OP已经指出的,第一次评估x时,它获取全局i在该特定时刻具有的任何值。在该初始评估之后,x不再受全局i的后续修改的影响。

Q2

按名称调用通常用于宏语言。那么,为什么不使用有史以来最著名的宏语言:C预处理器呢?

#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);
}

编译、运行并查看:25220。

按名称调用只需简单的搜索和替换;在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内的ij只是获取范围内发生的任何事情的当前值。

所以正确答案是B,对吧?嗯,差不多。。。正确答案取决于CCD_ 14的实现。假设print也执行按名称调用print定义了自己的局部变量i,那么这将极大地改变结果。试试这个:

#define print(num)  { int i = 0; printf("%dn", num); }

结果现在更改为15、20。

这可能是动态作用域不利于代码可维护性的最重要原因。函数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

最新更新