3.10.2 Проблемы с приоритетом операторов
Вы, возможно, заметили, что во многих примерах определения макросов выше каждое вхождение имени аргумента макроса заключено в скобки. Кроме того, вокруг всего определения макроса обычно присутствует ещё одна пара скобок. Вот почему лучше писать макросы именно таким образом.
Предположим, вы определили макрос следующим образом:
#define ceil_div(x, y) (x + y - 1) / y
целью которого является целочисленное деление с округлением вверх. (Одно из применений этой операции — вычисление количества int объектов, необходимых для хранения определённого числа char объектов.) Затем предположим, что он используется следующим образом:
a = ceil_div (b & c, sizeof (int));
→ a = (b & c + sizeof (int) - 1) / sizeof (int);
Это не выполняет задуманное действие. Правила приоритета операторов языка C делают его эквивалентным этому:
a = (b & (c + sizeof (int) - 1)) / sizeof (int);
А нам нужно вот это:
a = ((b & c) + sizeof (int) - 1)) / sizeof (int);
Определение макроса как
#define ceil_div(x, y) ((x) + (y) - 1) / (y)
дает желаемый результат.
Непредвиденное группирование может возникнуть и другим способом. Рассмотрим sizeof
ceil_div(1, 2). Он выглядит как выражение языка C, вычисляющее размер типа ceil_div (1, 2), но на самом деле означает нечто совершенно иное. Вот как он расширяется:
sizeof ((1) + (2) - 1) / (2)
Это будет вычислять размер целого числа и делить его на два. Правила приоритета поместили операцию деления вне sizeof, хотя предполагалось, что она будет внутри.
Скобки вокруг всего определения макроса предотвращают такие проблемы. Итак, вот рекомендуемый способ определить ceil_div:
#define ceil_div(x, y) (((x) + (y) - 1) / (y))
Далее: Поглощение точки с запятой, Предыдущее: Вложенность, Вверх: Ловушки макросов [Оглавление][Индекс]
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-7.5.0/cpp/Operator-Precedence-Problems.html