Приоритет && над ||

Поскольку я знаю, что логический оператор && имеет более высокий приоритет, чем || , При запуске кода:

 #include  int main() { int i = 1, j =1, k = 1; printf("%d\n",++i || ++j && ++k); printf("%d %d %d",i,j,k); return 0; } 

дает выход:

 1 2 1 1 

что возможно только тогда, когда ++i || ++j && ++k ++i || ++j && ++k оценивается следующим образом:

 (++i) || (++j && ++k) 

Но, согласно правилу приоритета оператора, его следует оценивать как:

 (++i || ++j) && (++k) 

и, следовательно, выход должен быть:

 1 2 1 2 

Что в этом плохого?

ПРИМЕЧАНИЕ. По моему мнению, я считаю, что оператор с более высоким приоритетом оценивается следующим образом ( если он оставлен ассоциативным ):
1. Оцените его левое выражение
2. Затем оцените его правильное выражение (если необходимо)
Я ошибаюсь?

Ты говоришь:

что возможно только тогда, когда ++i || ++j && ++k ++i || ++j && ++k оценивается следующим образом:

 (++i) || (++j && ++k) 

Но, согласно правилу приоритета оператора, его следует оценивать как:

 (++i || ++j) && (++k) 

Первая группировка правильная, поскольку приоритет && выше, чем приоритет || , Тогда выражение в целом оценивает LHS || , с побочным эффектом приращения i , который оценивается как true. Это означает, что RHS || (выражение && ) не оценивается вообще, потому что нет необходимости определять истинность общего выражения.

Итак, компилятор прав; вы неправильно поняли приоритет.


Почему первая группировка правильная? Согласно первой группировке || имеет более высокий приоритет, чем && . Что со мной не так?

Вы не понимаете приоритета, кажется, или не понимаете взаимодействия приоритета с порядком оценки. Первая группировка дает более высокий приоритет && .

Если у вас есть a + b * c , где * имеет более высокий приоритет, чем + , то он оценивается как a + (b * c) , не так ли? Изменить + на || и * на && а выражения изоморфны, а интерпретация аналогична.

Большая разница между арифметическим выражением и логическим выражением заключается в том, что операнды логического выражения должны оцениваться слева направо, но операнды арифметического выражения не выполняются; компилятор мог оценить b * c перед оценкой a (но должен выполнить оценку b * c перед выполнением добавления). Напротив, в логическом выражении ( a || b && c ) компилятор должен оценить a перед оценкой b && c , а когда a окажется true, он не должен оценивать b или c , не говоря уже о b && c ,

|| коротких замыканий оператора – если его первый операнд оценивает значение true (отличное от нуля), он не оценивает свой второй операнд.

Это также верно для && , он не использует свой второй операнд, если первый является ложным. Это оптимизация, которая возможна, потому что любое логическое значение OR true является истинным, и аналогичным образом любое логическое значение AND false всегда ложно.


Хорошо, так что вы сбиваете с толку приоритет с порядком оценки. Здесь нет ничего противоречивого:

 ++i || ++j && ++k 

группируется как

 (++i) || (++j && ++k) 

так как && имеет более высокий приоритет. Но тогда LHS операции OR истинна, поэтому вся RHS с ее операцией AND отбрасывается, она не оценивается.


К вашей заметке в редакции: да, вы ошибаетесь: приоритет оператора по- прежнему не совпадает с порядком оценки. Это просто группировка.

Во-первых, как вы сами сказали, && имеет более высокий приоритет, что означает, что группировка операндов должна быть

  (++i) || (++j && ++k) 

Почему вы говорите, что «в соответствии с приоритетом оператора» он должен быть (++i || ++j) && (++k) мне не понятен. Это просто противоречит тому, что вы сказали сами.

Во-вторых, приоритет операторов не имеет абсолютно никакого отношения к порядку оценки. Приоритет оператора диктует группировку между операторами и их операндами (т.е. приоритет оператора указывает, какой операнд принадлежит оператору).

Между тем, порядок оценки – совсем другая история. Он либо остается неопределенным, либо определяется совершенно другим набором правил. В случае || и && операторы порядок оценки действительно определяется как слева направо (с обязательным ранним завершением, когда это возможно).

Таким образом, правила приоритета операторов говорят вам, что группировка должна быть

  (++i) || ((++j) && (++k)) 

Теперь правила порядка оценки говорят вам, что сначала мы оцениваем ++i , тогда (если необходимо) мы оцениваем ++j , тогда (если необходимо) мы оцениваем ++k , тогда мы оцениваем && и, наконец, оцениваем || ,

Поскольку вы недопонимаете приоритет, попробуем разобраться с математическим примером. Умножение и деление имеют более высокий приоритет, чем сложение и вычитание. Это означает, что это выражение:

 a + b * c - d / e 

Можно написать так:

 a + (b * c) - (d / e) 

Поскольку вы правильно заявили, что && имеет более высокий приоритет, чем || , это выражение:

 i || j && k 

может быть написано так:

 i || (j && k) 

Вы можете подумать об этом как о том, что «операция с наивысшим приоритетом сначала начинается в скобках», если это помогает.

(Но приоритет отличается от оценки – если i истинно, тогда (j && k) никогда не будет оценен.)

Interesting Posts

java.lang.IllegalAccessError: попытался получить доступ к методу

Почему реализация libc ++ std :: string занимает 3-кратную память как libstdc ++?

Диалоговое окно JQuery UI с обратной записью на ASP.NET

Какие запросы вызывают обновления браузеров «F5» и «Ctrl + F5»?

Почему дополнительная константа автоматически не имеет значения по умолчанию nil

Ctrl + Backspace вставляет небольшой ящик вместо стирания

Есть ли возможность контролировать использование данных при использовании измеренных подключений?

Оператор <: <в scala

Как решить медленную Java `SecureRandom`?

Подключение к локальной сети – DOS для Windows 7

Как автоматически закрыть Terminal.app при выходе в OS X Lion?

Могу ли я использовать зарядное устройство с меньшим количеством ампера, чем оригинал?

преобразовать формат столбца data.frame из символа в фактор

Как вернуть пользовательский объект из запроса Spring JPA GROUP BY

Каков алгоритм вычисления Amazon-S3 Etag для файла размером более 5 ГБ?

Давайте будем гением компьютера.