Почему выражение 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, которое в конечном итоге делает это выражение правильным.