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スカラー自体 ( SV*C 用語では a ) を配置します。Perl の専門用語では、スタック要素は[2]にエイリアスされていると言います。計算理論では、引数は参照によって渡されると言うでしょう。$a

同じことが にも当てはまります++$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++呼ばれるまでに、 $a6本入っています。

printf呼ばれるまでに、 $a7本入っています。


回避策は、値のコピーを作成することです。

$ 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から、「渡された引数は配列 に表示され@_ます。したがって、2 つの引数で関数を呼び出した場合、それらは と に格納され$_[0]ます$_[1]。配列@_はローカル配列ですが、その要素は実際のスカラー パラメータのエイリアスです。 "

于 2013-05-15T16:43:02.793 に答える