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-11.4.0/cpp/Operator-Precedence-Problems.html