#include <iostream>
void main() {
int a(2);
std::cout << ((--a) * (++a)) << std::endl;
system("pause");
}
-
2А почему вдруг 2? – AnT stands with Russia Jul 17 '19 at 19:27
-
2Возможный дубликат вопроса: Понять где undefined behavour в арифметических выражениях – Fat-Zer Jul 17 '19 at 21:40
2 Answers
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 - то есть может произойти до, после, или даже одновременно.
- 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
Потому что вы используете предекрименты и преинкременты в выражении взаимодействуя с целочисленной переменной "a". получается 2 * 2 = 4
цитата
Согласно спецификации языка, разница между пре- и постинкрементом состоит в том, что при вычислении выражения значением результат является в одном случае старое, а в другом — новое значение инкрементируемой переменной. В случае простого применения в форме x++; (например, такое часто встречается в циклах) возвращаемое значение не используется, и смысл обеих форм строго одинаков, так что они компилируются в одинаковый объектный код.
В таком случае, взаимодействие с переменной "а" будет происходить изначально, когда а = 2 если вы используете пре-инкременты и пре-декрименты