使用动态范围调用名称

时间:2013-02-06 09:08:41

标签: c scope dynamic-binding dynamic-scope callbyname

我遇到了静态/动态范围的以下问题:

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

 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)

On Q2:在动态作用域中,首先在本地函数中搜索变量,然后在调用本地函数的函数中搜索,然后在调用该函数的函数中搜索,依此类推,向上调用堆栈。

按姓名呼叫:

print (i1 + j + 10) -> print (100 + 5 +10 ) -> 115

第二个电话将是

print(x) -> print(i1 + j) -> (100 + 20) = 120 // Evaluate again - Call be name.

这个答案是否正确? (不在选项中) 有什么我想念的吗? (动态绑定可能是?)

3 个答案:

答案 0 :(得分:3)

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("%d\n", num)

#define P(x) {     \
    int i = 10;    \
    print(x + 10); \
    i = 200;       \
    j = 20;        \
    print(x);      \
}

main() {
    P(i + j);
}

编译,运行,并查看:25,220。

按名称呼叫可以使用简单的搜索和替换;在P的正文中,将x的每一次出现都替换为i + j

int i = 10; 
print(i + j + 10);    // 10 + 5 + 10 = 25
i = 200;
j = 20;
print(i + j);         // 200 + 20 = 220

换句话说,ij里面的i + j只是在评估x时获取范围内的任何内容的现值。

所以正确答案是B,对吗?好吧,差不多......正确的答案取决于print的实施。 假设print实践按姓名调用 print定义了自己的局部变量i,那么这会大大改变结果。试试这个:

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

结果现在变为15,20。

这可能是动态作用域对代码可维护性不利的最重要原因。函数print中的实现更改(即使更改局部变量的名称也是微不足道的)可能会破坏更高级别的函数。

答案 1 :(得分:0)

在第二部分是按名称呼叫

i = 200行将更新本地i

现在,当print(x)被调用时,它将被print(i + j)=&gt; print(200 + 20)=&gt; 220

取代

答案 2 :(得分:0)

对于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