"Андрей Богатырев. Хрестоматия по программированию на Си в Unix" - читать интересную книгу автора

однако, что пробелы после # перед именем директивы вполне допустимы. В четвертом
случае показана характерная опечатка - символ ; после определения. В результате напи-
санный printf() заменится на

printf( "n=%d\n", 12; );

где лишняя ; даст синтаксическую ошибку.
В пятом случае ошибки нет, но нас ожидает неприятность в строке p=4-X; которая
расширится в строку p=4--2; являющуюся синтаксически неверной. Чтобы избежать подоб-
ной ситуации, следовало бы написать

p = 4 - X; /* через пробелы */

но еще проще (и лучше) взять макроопределение в скобки:

#define X (-2)

1.45. Напишите функцию max(x, y), возвращающую большее из двух значений. Напишите
аналогичное макроопределение. Напишите макроопределения min(x, y) и abs(x) (abs -
модуль числа). Ответ:

#define abs(x) ((x) < 0 ? -(x) : (x))
#define min(x,y) (((x) < (y)) ? (x) : (y))

Зачем x взят в круглые скобки (x)? Предположим, что мы написали

#define abs(x) (x < 0 ? -x : x )
вызываем
abs(-z) abs(a|b)
получаем
(-z < 0 ? --z : -z ) (a|b < 0 ? -a|b : a|b )

У нас появилась "дикая" операция --z; а выражение a|b<0 соответствует a|(b<0), с сов-
сем другим порядком операций! Поэтому заключение всех аргументов макроса в его теле
в круглые скобки позволяет избежать многих неожиданных проблем. Придерживайтесь этого
правила!
Вот пример, показывающий зачем полезно брать в скобки все определение:

#define div(x, y) (x)/(y)

При вызове

А. Богатырев, 1992-95 - 19 - Си в UNIX

z = sizeof div(1, 2);
превратится в
z = sizeof(1) / (2);

что равно sizeof(int)/2, а не sizeof(int). Вариант