【问题标题】:Call by Reference and Call by Value Result按引用调用和按值调用结果
【发布时间】:2015-09-26 05:34:36
【问题描述】:

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

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。

【问题讨论】:

    标签: pass-by-reference pascal call-by-value


    【解决方案1】:

    按值调用

    p中的xy是带实参的局部变量初始化,而i是全局变量,所以调用p( 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] 的值,它们没有改变。

    引用调用

    p 中的 xy 都是 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 在过程执行开始时使用实际参数的值进行初始化,并且,在程序执行结束,都复制回original变量addresses

    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

    【讨论】:

    • 感谢您的解释。你能提供call by value result的结果吗?
    • 我已经通过值结果添加了调用。
    • 不知道 Pascal 支持按名称调用和按值调用结果。这种模式是如何制定的?
    • 由于 Pascal 仅在标签中而不是在问题中明确显示,因此在我的回答中,我一般谈论的是受(不同版本)Pascal 影响或影响的语言的参数传递。例如,至少当前的 Pascal 编译器 (Free Pascal) 具有按值调用、按引用调用 (var)、按结果调用 (out)(以及按常量调用 (const)); Algol 60 有名称调用; Ada 和其他语言有按值结果调用 (in out)。
    • @brucebanner,你是对的,x 的当前值 2 被复制回 a[1]。我更正了答案。谢谢!
    【解决方案2】:
    procedure p(x, y: integer);
    begin
    end;
    

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

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

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

    【讨论】:

      猜你喜欢
      • 2014-08-10
      • 2013-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-24
      • 2014-02-09
      • 1970-01-01
      相关资源
      最近更新 更多