7

我想知道为什么以下输出7 7 6 7而不是5 6 6 7

my $a = 5;
printf("%d %d %d %d",$a,++$a , $a++ , $a);

我很确定这与参数编译的顺序有关

谢谢,

4

1 回答 1

14

在开始之前,让我指出,通常应该避免在表达式中设置和读取变量的情况。


首先,让我们看一下操作数的评估顺序。这不是为许多运算符定义的,但它是为列表运算符定义的。它被记录为以从左到右的顺序评估其操作数[1]。这意味着printf的参数按以下顺序评估:

  1. "%d %d %d %d"
  2. $a
  3. ++$a
  4. $a++
  5. $a

关键在于知道$a不会将值的副本$a放在堆栈上。它放置标量本身(a SV*,在 C 术语中)。在 Perl 行话中,我们说堆栈元素的别名$a[2]。在计算理论中,您会说参数是通过引用传递的。

也是如此++$a,但必须在堆栈上$a++放置一个副本。$a

这意味着我们可以将上述printf调用视为等价于

use Data::Alias qw( alias );

{
    local @_;
    alias $_[0] = "%d %d %d %d";
    alias $_[1] = $a;    # Places $a on the stack.
    alias $_[2] = ++$a;  # Adds one to $a and places $a on the stack.
    alias $_[3] = $a++;  # Places a copy of $a on the stack and adds one to $a.
    alias $_[4] = $a;    # Places $a on the stack.
    &CORE::printf;
 }

到时候$a++调用,$a包含6个。

到时候printf被调用,$a包含7个。


解决方法是复制这些值。

$ perl -le'$a = 5; my @b = ($a, ++$a, $a++, $a); print "@b";'
7 7 6 7

$ perl -le'$a = 5; my @b = (0+$a, 0+(++$a), $a++, $a); print "@b";'
5 6 6 7

  1. 来自perlop,“在列表上下文中,它只是列表参数分隔符,并将其两个参数都插入到列表中。这些参数也是从左到右评估的。”

  2. perlsyn中,“传入的任何参数都显示在数组中@_。因此,如果您调用带有两个参数的函数,这些参数将存储在$_[0]and中$_[1]。该数组@_是一个本地数组,但它的元素是实际标量参数的别名。 "

于 2013-05-15T16:43:02.793 回答