Pull to refresh

Comments 19

Что-то я не понял, почему в случае
$c = ($a + $a) + ($a++)
получили int(3)? Опечатка?
Сложение в левой скобке дает 2, во второй тоже 2, потом 2 и 2 складываются.
Или с фразой "инкремент имеет более высокий приоритет" что-то не так.

Там же пост инкремент, сначала к 2 добавляется $а со значением 1, потом $a инкрементируется (но уже поздно)

Тогда почему ($a + $a++) равно три, а не два?

Постинкремент в текущее выражение возвращает текущее значение переменной, а после этого увеличивает значение самой переменной. Оба примера в итоге сводятся к 2+1. Операнды в выражении инициализируются не в порядке упоминания, а в порядке выполнения операторов.


Если разложить примеры, то выйдет


// $c = $a + $a++;
$a = 1;
$c = $a; $a = $a + 1; // постинкремент в выражении
$c = $c + $a; // сложение

// $c = $a + $a + $a++;
$a = 1;
$c = $a + $a; // левое сложение
$c = $c + $a; $a = $a + 1; // постинкремент и правое сложение
Так почему в первом примере $a = $a + 1; идёт перед $c = $c + $a;, а во втором — после? Это как-то непоследовательно

Потому что


Операнды в выражении инициализируются не в порядке упоминания, а в порядке выполнения операторов.

В первом примере интерпретатор хочет произвести сложение, натыкается на $a++, выполняет и получает выражение "текущее значение А (уже равное двум) + старое значение А (ещё равное единице)" = 3.


Во втором примере он сначала выполняет первое слева сложение, получает $a + $a = 2; затем хочет выполнить следующее сложение, натыкается на $a++, выполняет его, а затем получает выражение "2 + старое значение А", результатом вычисления которого так же является тройка.


P.S. и да, в обоих примерах $a = $a+1; идёт после сложения. Смотри код внимательней: в одном примере одно сложение, в другом два.
Или, может, так понятней будет:


// $c = $a + $a + $a++;
$a = 1;
$c = $a + $a; // левое сложение
$b = $a; $a = $a + 1; // постинкремент
$c = $c + $b; // правое сложение
Операнды в выражении инициализируются не в порядке упоминания, а в порядке выполнения операторов.

Всё-таки порядок вычисления операндов — не определен (это прямо в документации PHP написано). Так что в одной версии PHP может посчитаться одним образом, а в другой — другим.
Может получиться и так, что из 2х групп ($a+$a) и ($a++), пост-инкремент ($a++) будет считаться первым и тогда сумма ($a+$a) уже будет равна 4, а общий результат будет 5.

Я отвечал на вопрос "почему оно возвращает 3 в обоих вариантах", а не "сколько оно должно возвращать по стандарту". Порядок вычисления операндов, всё-таки, в текущей версии интерпретатора реализован так как реализован и уже не изменится.


А про то, что он может измениться в следующем релиза, как раз, написано и в стандарте, и в переведённой вами заметке Никиты, прямо перед предложением о том, что так писать не надо.

Не совсем уверен в своих мыслях, но мне кажется это работает так, другого объяснения я не вижу:
Результат:
$tmp_2 = POST_INC $a

не $tmp_2=2 $a=1, а, наоборот, $tmp_2=1 $a=2. Т.е. $tmp_2 — это результат $a++, а не состояние $a

Ведь:
$a = 1;
$tmp_2 = $a++;
var_dump($a, $tmp_2); // int(2), int(1) 


$c = $a + $a + $a++ = ($a + $a) + ($a++) =  (1+1) + (1) 
$c = $a + $a++ = $a + ($a++) = 2+(1)

Видимо оп коды это еще не совсем справа команда, слева результат без сайд эффектов.
Т.е. опкоды — это скорее результат разложения кода на более простые операции и последовательности операций, а не линейный «машинный код»

Вот почему на код ревью я настаиваю, чтобы инкременты/декременты всегда были единственным выражением в инструкции. Если и пропускаю, то по невнимательности.

Согласен. Код должен быть одинаково понятен хоть новичку, хоть опытному программисту.
Код, который может прочитать только опытный программист — плохой код.

gcc -Wall тоже предупреждает, хотя логично чтобы это было по умолчанию.


Вообще же по спецификации C/C++ порядок выполнения действий в пределах выражения отдаётся на усмотрение компилятору и не определен совершенно официально, любое "определенное" поведение конкретного компилятора — это частный случай.

А почему так есть объяснение?

Для того чтобы можно было оптимизировать выполнение операций если конечный результат не зависит от порядка вычисления.


К примеру, если у нас есть нечто вроде:


x = a * b + c * d;

и при этом значения c или d уже находятся в регистрах в связи с более ранним использованием, компилятор может сгенерировать код для вычисления правого слагаемого перед вычислением левого.

Насколько я помню, выражения типа a + a++ в плюсах — это вообще undefined behavior, потому взятие значения левого операнда и инкремент правого unsequenced относительно друг друга, а так делать по стандарту нельзя. Поэтому тут вообще может быть любой удобный компилятору результат.
Когда-то давно, когда деревья были высокие, я читал книжку по PHP5 и там говорились что если плюсики после переменной, то она измениться после выполнения выражения, а тут здрасте. И что спустя 15 лет нельзя было это исправить?

Так она и изменяется после выполнения. Вопрос лишь когда это выполнение происходит в составе сложного выражения.

Каждый опкод имеет максимум 2 операнда и опциональный результат.

И extend, который может кардинально поменять работу опкода

Sign up to leave a comment.

Articles