使用动态范围按名称调用

标签 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. If the programming language uses static scoping and call by need parameter passing mechanism, the values printed by the above program are

(A) 115, 220 (B) 25, 220 (C) 25, 15 (D) 115, 105

Q2. If the programming language uses dynamic scoping and call by name parameter passing mechanism, the values printed by the above program are

(A) 115, 220 (B) 25, 220 (C) 25, 15 (D) 115, 105

我的想法:

关于问题 1:由于它是静态范围,并且根据需要调用,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)

关于问题 2:在动态作用域中,您首先在局部函数中搜索变量,然后在调用局部函数的函数中搜索,然后在调用该函数的函数中搜索,依此类推,向上调用堆栈。

根据名字调用:

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

第二次调用将是

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

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

最佳答案

Q1

OP 的答案是正确的 (D)。实际上,由于P执行过程中没有修改全局i,所以call by needcall by 没有区别值(value)

这是一个示例,它确实有所作为:

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 的正文中,用 i + j 替换每次出现的 x

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

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

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

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

结果现在变为 15、20。

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

关于使用动态范围按名称调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14725225/

相关文章:

java - 静态与。 Java中的动态绑定(bind)

c - 如何将 N 个单元格从数组 1 复制到数组 2 ,并接收错误的返回值?

javascript - 仅在作用域内附加到字​​符串原型(prototype)的函数

java - 由于作用域,对象未初始化

c++ - 我应该怎么做才能看到实际的静态和动态绑定(bind)? [C++]

java - c++动态绑定(bind)和java动态绑定(bind)有什么区别?

c++ - 在没有比较运算符的情况下查找 2 个数字之间的最小值

c - 多次加载内核模块(snd-aloop)

c - extern 如何在 C 中工作,内部函数

C# foreach 循环导致 CS 0246 Type or namespace could not be found