История вопроса
Приоритет операторов был введён в C для управления порядком вычислений в математических и логических выражениях. Несмотря на то, что математические операторы имеют исторически ожидаемый приоритет (как в алгебре), появление множества новых операторов (логических, побитовых, присваивания и т.д.) усложнило картину. Чтобы снизить вероятность ошибок и повысить читаемость, появился официальный список приоритетов и ассоциативности операторов.
Проблема
За счет большего числа операторов и их различной природы (арифметические, сравнения, присваивания, логические, индексация), возникают неоднозначности при составлении комплексных выражений. Неправильное понимание порядка их применения приводит к логическим ошибкам и не всегда очевидным багам, особенно при сочетании побитовых и логических операторов, указателей, инкрементов и тернарного оператора.
Решение
Пример кода:
#include <stdio.h> int main() { int a = 1, b = 2, c = 3, d; d = a + b * c; // b*c выполняется раньше: d = 1 + (2*3) = 7 printf("%d ", d); d = a + b << 1; // a + b = 3, затем 3 << 1 (6) printf("%d ", d); d = a < b ? a++ : b++; printf("%d ", d); // a < b истина => d = a (1), a увеличится после }
Ключевые особенности:
Какой результат даст выражение x = y > z ? y : z; если забыть скобки?
Ответ: Тернарный оператор ?: имеет ниже приоритет, чем >. Сначала вычисляется (y > z), а затем выбирается между y и z. Но если комбинировать с присваиванием, возможны неожиданные эффекты. Лучше всегда использовать скобки x = (y > z) ? y : z;.
*Какой результат даст выражение p++ и почему?
Ответ: Оператор постинкремента (++) имеет более высокий приоритет, чем разыменование (*), поэтому *p++ становится *(p++): сначала p используется и увеличивается, только потом разыменовывается, что может отличаться от *++p (разыменование после инкремента).
Почему выражение a & b == c не работает как ожидается?
Ответ: Оператор == имеет более высокий приоритет, чем &, поэтому выражение анализируется как a & (b == c), а не (a & b) == c, что породит неожиданный результат. Для желаемой логики нужно использовать скобки.
if ((a & b) == c) { ... }
Негативный кейс
При оптимизации кода программист объединил несколько операторов без скобок: if( mask & flag == 0 ) ..., в результате логика проверки работала неверно и привела к сбою в работе системы.
Плюсы:
Минусы:
Позитивный кейс
Использование явной группировки: if( (mask & flag) == 0 ) ..., логика прозрачна, легко менять флаги.
Плюсы:
Минусы: