Мне было интересно, почему следующие выходные данные 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
в стек. Он помещает сам скаляр (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
Из perlop: "В контексте списка это просто разделитель аргументов списка, и вставляются оба его аргумента. в список. Эти аргументы также оцениваются слева направо».
Из perlsyn: "Все переданные аргументы отображаются в массиве @_
. Следовательно, если вы вызвали функция с двумя аргументами, они будут храниться в $_[0]
и $_[1]
. Массив @_
является локальным массивом, но его элементы являются псевдонимами для фактических скалярных параметров».
&CORE::printf
, но вы поняли идею.)
- person ikegami; 15.05.2013
printf
значения или нет. К моменту вызова printf
$a
уже содержит 7
. Замените printf
своим собственным сабвуфером, если хотите поэкспериментировать.
- person ikegami; 15.05.2013
@b
после my @b = ($a, ++$a, $a++, $a);
, это тоже 7767. )
- person raina77ow; 15.05.2013