Почему выражение a = a + b - (b = a) дает предупреждение о точке последовательности в С++?
Ниже приведен тестовый код:
int main()
{
int a = 3;
int b = 4;
a = a + b - (b = a);
cout << "a :" << a << " " << "b :" << b << "\n";
return 0;
}
При компиляции это дает следующее предупреждение:
> $ g++ -Wall -o test test.cpp test.cpp: In function ‘int main()’:
> test.cpp:11:21: warning: operation on ‘b’ may be undefined
> [-Wsequence-point]
Почему операция может быть undefined?
По моему мнению, сначала подвыражение (b = a)
должно быть оценено из-за более высокого приоритета(), установив таким образом b = a. Тогда, поскольку "+" и "-" имеют одинаковый приоритет, выражение будет оцениваться лево-ассоциативно. Таким образом, a + b
следует оценивать следующим образом, и, наконец, результат (b = a)
следует вычесть из a + b
. Я не вижу здесь правила последовательности).
Ответы
Ответ 1
Существует разница между оцениваемым выражением и выполнением его побочных эффектов.
Выражение присваивания b = a
будет оцениваться перед вычитанием из-за более высокого приоритета скобок. Это даст значение a
в результате оценки. Однако запись этого значения в b
может не завершиться до следующей точки последовательности, которая в этом случае является окончанием полного выражения. Таким образом, конечный результат общего выражения undefined, поскольку вычитание может принимать значение b
до или после назначения.
Ответ 2
В С++ подвыражения в арифметических выражениях не имеют временного порядка.
a = x + y;
Сначала оценивается x
, или y
? Компилятор может выбрать либо, либо он может выбрать что-то совершенно другое. Порядок оценки - это не то же самое, что приоритет оператора: строго определено приоритет оператора, а порядок оценки определяется только детализацией, что ваша программа имеет точки последовательности.
Фактически, на некоторых архитектурах можно испускать код, который одновременно оценивает как x
, так и y
- например, архитектуры VLIW.
Ответ 3
Чтобы решить эту проблему, отделите их в двух разных операторах.
PS: Не забывайте, что люди могут ошибаться, выполняя арифметические операции. Поэтому лучше сделать операции более четкими, разделив их в разных операторах. Надеюсь, я помог.
int main()
{
int a = 3;
int b = 4;
/* Two different Statements*/
b = a;
/* or a = a + b - a */
a = a + b - b;
cout<<"a :"<<a<<" "<<"b :"<<b<<"\n";
return 0;
}
Ответ 4
a = b + a - a;
просто написано как
a = b + a - (b = a)
------ → (exp 1)
Следующие три результата аналогичны (exp 1)
a = (b + a - (b = a));
a = ((b + a) - (b = a));
a = (b + a) - (b = a);
Наблюдения
+, - имеют тот же приоритет, что и ассоциация слева направо
Следовательно, сначала выполняется "b + a", а затем "a" присваивается значение "b" перед вычитанием
Теперь соблюдайте следующие
Когда a = 10 и b = 20;
a = (b = a) - b + a;
======= → a = 10; b = 10
a = ((b = a) - b + a);
======= → a = 10; b = 10
a = ((b = a) - (b + a));
======= > a = -10; b = 10
Из приведенных выше выражений ясно, что даже если выполняется самая внутренняя скобка, сначала следует ассоциативность, а затем приоритет
Примечание:
Чтобы избежать путаницы между приоритетом внешней и внутренней круглых скобок
Рассмотрим следующее выражение
a = (b + a - (b = a))
===== > Фактический результат = > a = 20, b = 10;
было бы = 10, b = 10; (если приоритет является первичным по сравнению с ассоциативностью)
Таким образом, в приведенном выше примере мы можем сказать, что ассоциативность является первичной по сравнению с приоритетом
Ответ 5
int main()
{
int a = 3;
int b = 4;
/* Two different Statements*/
b = a;
/* or a = a + b - a */
a = a + b - b;
cout<<"a :"<<a<<" "<<"b :"<<b<<"\n";
return 0;
}
неправильная идея, поскольку вывод не заменяет числа.
Утверждение a = a + b - (b = a);
вычисляет сумму a + b сначала с исходными значениями, а затем, когда дело касается вычитания, тогда только присваивается значение a в b.
Мое мнение в этом случае состоит в том, чтобы преобразовать выражение в префиксную нотацию, и у вас будет лучшее понимание.
Постфиксное выражение - + АВ = ВА
ясно, что сначала вычисляется a + b, а затем только значение b присваивается значению a, которое в конечном итоге делает это выражение правильным.