3
#include <iostream>

void main() {

    int a(2);
    std::cout << ((--a) * (++a)) << std::endl;

    system("pause");

}
Viktorov
  • 7,195
  • 10
  • 37
  • 66
llollcat
  • 587

2 Answers2

9

warning: operation on 'a' may be undefined [-Wsequence-point] — (c) GCC

warning: multiple unsequenced modifications to 'a' [-Wunsequenced] — (c) Clang

Так делать нельзя. Изменение переменной два раза "в одном месте" (грубо говоря) вызывает неопределенное поведение, и результат выполнения такой программы может быть любым.

Подробнее можно прочитать вот тут: Order of evaluation.

А еще здесь: Понять где undefined behavour в арифметических выражениях
и здесь: Undefined behavior and sequence points.


Попробую кратко объяснить.

Если у вас есть выражение вида A * B, то A не обязательно будет вычислено до B. Пример:

#include <iostream>

int f1() { std::cout << '1'; return 1; }

int f2() { std::cout << '2'; return 2; }

int main() { int x = f1() * f2(); }

Этот код может напечатать 12 или 21, в зависимости от желания левой пятки компилятора.

(Так же ведут себя +, -, *, /, %, ..., но не =, <<, >>, &&, ||, ... - подробности по самой верхней ссылке.)

Казалось бы, в случае ++a * --a не должно быть важно, какой операнд вычисляется первым. Но:

If a side effect on a scalar object is unsequenced relative to another side effect on the same scalar object, the behavior is undefined. — cppreference

Перевод:

Если побочный эффект1, действующий на скалярную переменную2, не упорядочен3 относительно другого побочного эффекта, действующего на ту же переменную, то поведение не определено.


1 Здесь это означает изменение значения переменной a в результате вычисления ++a или --a.

2 Т.е. на числовую переменную, а не на объект класса или что-то еще; здесь - на a.

3 Unsequenced - то есть может произойти до, после, или даже одновременно.

HolyBlackCat
  • 27,445
  • 3
  • 27
  • 40
  • Могу ли я принудительно расставить порядок действий для компилятора? К примеру, int x = (f1()) * f2() – llollcat Jul 17 '19 at 20:47
  • @llollcat Нет, здесь скобки ничего не поменяют. Можно так: int a = f1(); int b = f2(); int x = a * b; - тогда точно в нужном порядке посчитает. – HolyBlackCat Jul 17 '19 at 20:52
-7

Потому что вы используете предекрименты и преинкременты в выражении взаимодействуя с целочисленной переменной "a". получается 2 * 2 = 4

цитата

Согласно спецификации языка, разница между пре- и постинкрементом состоит в том, что при вычислении выражения значением результат является в одном случае старое, а в другом — новое значение инкрементируемой переменной. В случае простого применения в форме x++; (например, такое часто встречается в циклах) возвращаемое значение не используется, и смысл обеих форм строго одинаков, так что они компилируются в одинаковый объектный код.

В таком случае, взаимодействие с переменной "а" будет происходить изначально, когда а = 2 если вы используете пре-инкременты и пре-декрименты