I was wondering why the following outputs 7 7 6 7
instead of 5 6 6 7
my $a = 5;
printf("%d %d %d %d",$a,++$a , $a++ , $a);
I'm pretty sure it has something to do with the order of parameters compilation
Thanks,
Prefix Increment and Decrement Operators: ++ and --The prefix increment operator (++) adds one to its operand; this incremented value is the result of the expression. The operand must be an l-value not of type const . The result is an l-value of the same type as the operand.
Postfix operators are unary operators that work on a single variable which can be used to increment or decrement a value by 1(unless overloaded). There are 2 postfix operators in C++, ++ and --.
The main difference between prefix and postfix is that the prefix is a notation that writes the operator before operands while the postfix is a notation that writes the operator after the operands. Notation is the way of writing arithmetic expressions. There are various notations to write an arithmetic expression.
Postfix increment and decrement has higher precedence than prefix increment and decrement. The operand must have integral, floating, or pointer type and must be a modifiable l-value expression (an expression without the const attribute). The result is an l-value.
Before I start, let me point out that one should generally avoid situations where one you both sets and reads a variable within an expression.
First, let's look at operand evaluation order. This isn't defined for many operators, but it is defined for the list operator. It's documented to evaluate its operands in left-to-right order[1]. That means that printf
's arguments are evaluated in the following order:
"%d %d %d %d"
$a
++$a
$a++
$a
The key lies in knowing that $a
doesn't place a copy of the value of $a
on the stack. It places the scalar itself (a SV*
, in C terms). In Perl jargon, we say the stack element is aliased to $a
[2]. In computing theory, you'd say the arguments are passed by reference.
And the same goes for ++$a
, but $a++
necessarily places a copy of $a
on the stack.
This means we can view the above printf
call as equivalent to
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;
}
By the time $a++
is called, $a
contains 6.
By the time printf
is called, $a
contains 7.
The workaround is to make copies of the values.
$ 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
From perlop, "In list context, it's just the list argument separator, and inserts both its arguments into the list. These arguments are also evaluated from left to right."
From perlsyn, "Any arguments passed in show up in the array @_
. Therefore, if you called a function with two arguments, those would be stored in $_[0]
and $_[1]
. The array @_
is a local array, but its elements are aliases for the actual scalar parameters."
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With