なぜ次の出力7 7 6 7
の代わりに5 6 6 7
my $a = 5;
printf("%d %d %d %d",$a,++$a , $a++ , $a);
パラメータのコンパイルの順序と関係があると確信しています
ありがとう、
なぜ次の出力7 7 6 7
の代わりに5 6 6 7
my $a = 5;
printf("%d %d %d %d",$a,++$a , $a++ , $a);
パラメータのコンパイルの順序と関係があると確信しています
ありがとう、
始める前に、一般に、式内で変数の設定と読み取りの両方を行う状況は避けるべきであることを指摘しておきます。
まず、オペランドの評価順序を見てみましょう。これは多くの演算子では定義されていませんが、リスト演算子では定義されています。オペランドを左から右の順序で評価することが文書化されています[1]。つまり、printf
の引数は次の順序で評価されます。
"%d %d %d %d"
$a
++$a
$a++
$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++
呼ばれるまでに、 $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