Ниже приведен тестовый код:
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]
Почему операция может быть неопределенной?
Согласно моему пониманию, сначала подвыражение (b = a)
должен оцениваться из-за более высокого приоритета (), поэтому установка b = a. Тогда, поскольку «+» и «-» имеют одинаковый приоритет, выражение будет оцениваться левоассоциативно. Таким образом, a + b
следует оценить следующий, и, наконец, результат (b = a)
следует вычесть из a + b
, Я не вижу ни одного правило точки последовательности нарушается здесь.
Есть разница между выражением оценивали и завершение его побочные эффекты.
b = a
Выражение присваивания будет оцениваться перед вычитанием из-за более высокого приоритета в скобках. Это обеспечит ценность a
в результате оценки. Запись этого значения в b
однако может не завершиться до следующей точки последовательности, которая в этом случае является концом полного выражения. Поэтому конечный результат всего выражения не определен, поскольку вычитание может принимать значение b
до или после назначения.
В C ++ подвыражения в арифметических выражениях не имеют временного упорядочения.
a = x + y;
Является x
оценивается первым или y
? Компилятор может выбрать либо, либо он может выбрать что-то совершенно другое. Порядок оценки не то же самое, что и приоритет оператора: приоритет оператора строго определен, а порядок вычисления определяется только для степени детализации, в которой ваша программа имеет точки последовательности.
Фактически, на некоторых архитектурах возможно испускать код, который оценивает как x
а также y
в то же время — например, архитектуры VLIW.
Чтобы решить это, разделите их на два разных утверждения.
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;
}
a = b + a - a;
просто написано как
a = b + a - (b = a)
—— >> (опыт 1)
Следующие три результата такие же как (exp 1)
a = (b + a - (b = a));
a = ((b + a) - (b = a));
a = (b + a) - (b = a);
наблюдения
+, — операторы имеют такой же приоритет, а также ассоциативность слева направо
Следовательно, сначала выполняется «b + a», а затем перед вычитанием «a» присваивается значение «b».
Теперь соблюдайте следующее
Когда а = 10 и б = 20;
a = (b = a) - b + a;
=======> a = 10; б = 10
a = ((b = a) - b + a);
=======> a = 10; б = 10
a = ((b = a) - (b + a));
=======> a = -10; б = 10
Из приведенных выше выражений ясно, что даже если сначала выполняется внутренняя скобка, сначала следует ассоциативность, а затем приоритет
Замечания:
Чтобы избежать путаницы между приоритетом внешней и внутренней скобки
Рассмотрим следующее выражение
a = (b + a - (b = a))
=====> Фактический результат => a = 20, b = 10;
было бы а = 10, б = 10; (если приоритет является основным по сравнению с ассоциативностью)
Таким образом, в приведенном выше примере мы можем сказать, что ассоциативность является первичной по сравнению с предшествованием