Какие операторы в C имеют неправильный приоритет? - PullRequest
0 голосов
/ 17 февраля 2019

В разделе "Введение" K & R C (2E) есть этот абзац:

C, как и любой другой язык, имеет свои недостатки.Некоторые из операторов имеют неправильный приоритет;...

Какие это операторы?Как неправильны их приоритеты?

Является ли этот одним из этих случаев?

Ответы [ 4 ]

0 голосов
/ 17 февраля 2019

Неправильно может показаться слишком резким.Обычные люди, как правило, заботятся только об основных операторах, таких как +-*/^, и если они не работают так, как они пишут в математике, это можно назвать неправильно .К счастью, в C это «по порядку» (кроме оператора мощности, которого не существует)

Однако есть некоторые другие операторы, которые могут работать не так, как ожидают многие.Например, побитовые операторы имеют меньший приоритет, чем операторы сравнения , что уже упоминалось Эриком Постпишилом.Это менее удобно , но все же не совсем "неправильно", потому что раньше для них не было никакого определенного стандарта.Они были изобретены в прошлом веке, когда появились компьютеры

Другим примером являются операторы сдвига << >>, которые имеют более низкий приоритет, чем +-.Сдвиг рассматривается как умножение и деление, поэтому люди могут ожидать, что оно должно быть на более высоком уровне, чем +-.Написание x << a + b может заставить многих подумать, что это x * 2 a + b , пока они не посмотрят на таблицу приоритетов.Кроме того, (x << 2) + (x << 4) + (y << 6) также менее удобно, чем простые добавления без скобок


В других языках есть много реальных примеров "неправильного" приоритета

0 голосов
/ 17 февраля 2019

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

Исторически C развивался без &&.Чтобы выполнить логическую операцию И, люди будут использовать побитовое И, поэтому a==b AND c==d будет выражено как a==b & c==d.Чтобы облегчить это, == имел более высокий приоритет, чем &.Хотя && был добавлен к языку позже, & застрял с его приоритетом ниже ==.

В общем, люди могли бы хотеть писать выражения, такие как (x&y) == 1 гораздо чаще, чем x & (y==1).Поэтому было бы лучше, если бы & имел более высокий приоритет, чем ==.Следовательно, люди недовольны этим аспектом приоритетности оператора C.

Это обычно относится к &, ^ и |, имеющим более низкий приоритет, чем ==, !=, <,>, <= и >=.

0 голосов
/ 17 февраля 2019

Существует четкое правило приоритета, которое неопровержимо.Правило настолько ясно, что для строго типизированной системы (думаю, Паскаль) неправильный приоритет даст явные недвусмысленные синтаксические ошибки во время компиляции.Проблема с C состоит в том, что, поскольку его система типов является laissez faire, ошибки оказываются более логичными ошибками, приводящими к ошибкам, а не ошибкам, которые можно отловить во время компиляции.

Правило

Пусть○ □ два оператора с типом

○: α × α → β
□: β × β → γ
, а α и γ - разные типы.

Тогда

x ○ y □ z может означает только (x ○ y) □ z с присвоением типа
x: α, y: α, z: β

, тогда какx ○ (y □ z) будет ошибкой типа, потому что ○ может принимать только α, тогда как правильное подвыражение может создавать только γ, который не является α

Теперь позволяет

Применить этоC

По большей части C понимает правильно

(==): число × число → логическое значение
(&&): логическое значение логическое значение логическое значение логическое значение логическое значение * логическое значение

поэтому && должно быть ниже == и это так

Аналогично

(+): число × число → число
(==): число × число → логическое значение

и так (+) должно быть выше (==), что еще раз правильно

Однако в случае побитовых операторов

символ & / |из двух битовых комбинаций, иначе числа производят число, то есть
(&), (|): число × число → число
(==): число × число → логическое значение

И так типичнозапрос маски например.x & 0x777 == 0x777
может иметь смысл только в том случае, если (&) рассматривается как арифметический оператор, т. Е. Выше (==)

C ставит его ниже, что в свете приведенных выше правил типов неверно

Конечно, я выразил вышеизложенное в терминах математики / вывода типов

В более прагматичных терминах C x & 0x777 == 0x777 естественно группируется как x & (0x777 == 0x777) (при отсутствии явных скобок)

Когда такая группировка может иметь законное использование?
Я (лично) не верю, что существует какое-либо неофициальное утверждение Денниса Ричи

о том, что эти прецеденты неверны,более формальное обоснование

0 голосов
/ 17 февраля 2019

Зависит от того, какое соглашение о приоритете считается «правильным».Нет закона физики (или земли), требующего, чтобы приоритет был определенным образом;с течением времени он развивался в процессе.

В математике приоритет оператора обычно принимается как «БОДМАС» (скобки, порядок, деление, умножение, сложение, вычитание).Скобки идут первыми, а вычитание - последними. Порядок математических операций |BODMAS Порядок операций

Приоритет оператора в программировании требует большего количества правил, поскольку имеется больше операторов, но вы можете сравнить его с BODMAS.

Схема приоритета ANSI C изображена здесь: https://en.cppreference.com/w/c/language/operator_precedence

Как вы можете видеть, Унарное сложение и вычитание находятся на уровне 2 - ВЫШЕ Умножение и деление на уровне 3. Это может сбить с толкуматематик в поверхностном чтении, как и приоритет вокруг приращения и уменьшения суффикса / постфикса.

В этой связи ВСЕГДА стоит рассмотреть вопрос о добавлении скобок в ваш математический код - даже там, где синтаксически нет необходимости - чтобы убедиться, чтоЧЕЛОВЕК читатель, что ваше намерение ясно.Делая это, вы ничего не теряете (хотя вы, возможно, немного огорчены изнуренным рецензентом кода, в котором вы можете вспомнить об управлении рисками кодирования).Вы можете потерять читабельность, но намерение всегда более важно при отладке.

И да, предоставленная вами ссылка является хорошим примером.Это привело к многочисленным дорогостоящим производственным ошибкам.

...