2

好吧,我和我的朋友就下面的代码进行了辩论。我们对它产生的输出有点困惑。有人可以澄清以下代码的引用调用和值调用结果吗?

program params;
    var i: integer;
    a: array[1..2] of integer;

    procedure p(x,y: integer);
    begin
        x := x + 1;
        i := i + 1;
        y := y + 1;
    end;

begin
    a[1] := 1;
    a[2] := 2;
    i := 1;
    p( a[i],a[i] );
    output( a[1],a[2] );
end.

在参数通过值结果和引用传输到过程 p 的情况下,此程序的结果输出。

4

2 回答 2

6

按值调用

xand yin是用实参初始化p的局部变量,while是全局变量,所以调用等价于:ip( a[i],a[i] )

x := 1  /* The value of a[i] */
y := 1  /* The value of a[i] */

x := 2  /* x + 1 */
i := 2  /* i + 1 */
y := 2  /* y + 1 */

最后打印值 1、2,因为它们是 的值a[1]a[2]没有改变。

通过引用调用

xyin都是and (again)p的别名(从调用过程开始),所以调用等价于:a[1]a[1]i = 1

a[1] := 2  /* a[1] + 1 */
i    := 2  /* i + 1 */
a[1] := 3  /* a[1] + 1 */

最后打印值 3、2。

按名称呼叫

当简单变量作为参数传递时,按名称调用等同于按引用调用,但在传递表示内存位置的表达式(如下标)时则不同。在这种情况下,每次遇到实际参数时都会重新评估它。所以在这种情况下,这是调用的效果p( a[i],a[i] )

a[1] := 2  /* since i = 1, the result is equal to a[1] + 1 */
i    := 2  /* i + 1 */
a[2] := 3  /* since i is now 2, the result is equal to a[2] + 1 */

最后打印值 2、3。在实践中,实现调用一个匿名函数(“thunk”),每次它必须评估一个参数。

按值调用结果

只是为了完成讨论,这里是值结果参数传递的情况,其中xy在过程执行开始时使用实际参数的值进行初始化,并且在过程执行结束时,被复制回原来的变量地址

x := 1       /* The value of a[i] */
y := 1       /* The value of a[i] */

x := 2       /* x + 1 */
i := 2       /* i + 1 */
y := 2       /* y + 1 */

a[1] := 2    /* the value of x is copied back to a[1] */
a[1] := 2    /* the value of y is copied back to a[1] (not a[2]!) */

最后打印值 2, 2。

有关传递参数的不同方式的讨论,请参见this

于 2015-09-26T06:30:06.137 回答
0
procedure p(x, y: integer);
begin
end;

在这种情况下,作为参数传递的变量永远不会被修改。它们被复制到两个寄存器(可能是 x:EAX 和 y:ECX)或堆栈。(取决于编译器 ABI)

procedure p(var x, y: integer);
begin
end;

在这种情况下,原始参数被修改。x并且y是指向作为参数传递的原始变量的指针。

于 2015-09-26T06:12:30.877 回答