Подтвердить что ты не робот

Изменяется ли порядок операций внутри выражения if?

Недавно я наткнулся на то, что, как я думал, понял сразу с места в карьер, но, думая больше об этом, я хотел бы понять, почему он работает так, как он.

Рассмотрим приведенный ниже код. (x-- == 9) явно оценивается, а (y++ == 11) - нет. Моя первая мысль заключалась в том, что логический && срабатывает, видит, что выражение уже стало ложным и выкидывает перед оценкой второй части выражения.

Чем больше я думаю об этом, тем больше я не понимаю, почему это так ведет себя. Как я понимаю, логические операторы опускаются ниже операций приращения в порядке приоритета. Не следует ли оценивать (y++ == 11), хотя общее выражение уже стало ложным?

Другими словами, не должен ли порядок операций определять, что (y++ == 11) оценивается до того, как оператор if понимает, что выражение в целом будет ложным?

#include <iostream>
using namespace std;

int main( int argc, char** argv )
{
    int x = 10;
    int y = 10;

    if( (x-- == 9) && (y++ == 11) )
    {
        cout << "I better not get here!" << endl;
    }

    cout << "Final X: " << x << endl;
    cout << "Final Y: " << y << endl;
    return 0;
}

Вывод:

Final X: 9
Final Y: 10
4b9b3361

Ответ 1

логические операторы опускаются ниже операций приращения в порядке старшинство.

Порядок приоритета - это не порядок исполнения. Это совершенно разные понятия. Порядок приоритета влияет только на порядок выполнения в той мере, в какой операнды оцениваются перед их оператором, а порядок приоритетов помогает рассказать вам, какие операнды для каждого оператора.

Операторы короткого замыкания являются частичным исключением даже для правила, в котором операнды оцениваются перед оператором, поскольку они оценивают LHS, тогда оператор имеет право сказать, следует ли оценивать RHS, может быть, RHS оценивается, тогда вычисляется результат оператора.

Не думайте, что операции с более высоким приоритетом выполняются в первую очередь. Подумайте о том, что они "привязываются сильнее". ++ имеет более высокий приоритет, чем &&, а в выражении x ++ && y ++ приоритет оператора означает, что ++ "связывается более тесно" с y, чем &&, и поэтому выражение в целом эквивалентно (x++) && (y++), а не (x++ && y) ++.

Ответ 2

Не следует оценивать (y++ == 11), хотя общее выражение уже стало false?

Нет: короткое замыкание операторов && и ||: они оцениваются слева направо и, как только результат выражения известен, оценка останавливается (то есть, как только выражение Известно, что false в случае серии && или true в случае серии ||) (*).

Нет смысла делать дополнительную работу, которая не требуется. Это короткозамкнутое поведение также весьма полезно и позволяет писать код терминатора. Например, если указатель на объект struct-type, вы можете проверить, является ли указатель нулевым, а затем разыменовать указатель в последующем подвыражении, например: if (p && p->is_set) { /* ... */ }.


(*) Обратите внимание, что в С++ вы можете перегружать операнды && и || для типа класса, и если вы это делаете, они теряют свое свойство короткого замыкания (обычно не рекомендуется перегружать && и || по этой причине).

Ответ 3

Приоритет и ассоциативность не определяют порядок выполнения операций. Они определяют, как операции сгруппированы, то есть в следующем выражении:

x && y++

... более низкий приоритет && говорит, что он сгруппирован, как если бы он был:

x && (y++)

а не как

(x && y)++

В вашем выражении относительный приоритет && и ++ не имеет значения, потому что вы все равно разделили эти операторы с круглыми скобками.

Группировка (и, следовательно, приоритет и ассоциативность) определяют, какое значение имеет каждый оператор; но он ничего не указывает о том, когда он это делает.

Для большинства операторов порядок, в котором выполняются операции, не указан, однако в случае && указано сначала оценить левый операнд, а затем оценивать только правый операнд, если результат левый операнд был отличным от нуля.

Ответ 4

Нет. Порядок приоритета просто решает, получишь ли вы это:

A && B

A x-- == 9 и B y++ == 11) или

A == B == C

A x--, B - 9 && y++, а C равно 11).

Очевидно, мы имеем дело с первым случаем. Короткое замыкание полностью применяется; если A истинно, то B не оценивается.

Ответ 5

Условные операторы оценивают слева направо и останавливаются, как только результат известен (И с ложностью или OR с истинным значением).

Ответ 6

Стандарт

C не диктует какой-либо конкретный порядок оценки выражения в if. Поэтому поведение будет специфичным для компилятора, и использование этого стиля кодирования не переносится. Вы сталкиваетесь с этой проблемой, потому что приращение/уменьшение значения является пост-операцией, но стандарт говорит как пост-операция выражения, где используется переменная. Поэтому, если компилятор считает, что ваше выражение используется как одно значение переменной x или y, вы увидите один результат. Если компилятор считает, что выражение цельное, если выражение оценки, то вы увидите другой результат. Надеюсь, это поможет.