Изменяется ли порядок операций внутри выражения 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
Ответы
Ответ 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, вы увидите один результат. Если компилятор считает, что выражение цельное, если выражение оценки, то вы увидите другой результат. Надеюсь, это поможет.