Во избежание ошибок при вычислении выражений параметры макроопределения необходимо заключать в скобки.
#define идентификатор1 (идентификатор2,...) строкаПример:
#define abs(A) (((A) > 0)?(A): -(A))Каждое вхождение выражения abs(arg) в тексте программы заменяется на
((arg) > 0)? (arg): -(arg),причем параметр макроопределения А заменяется на arg.
Пример:
#define nmem(P,N)\(P) -> p_mem[N].u_longСимвол \ продолжает макроопределение на вторую строчку. Это макроопределение уменьшает сложность выражения, описывающего массив объединений внутри структуры.
Макроопределение с аргументами очень похоже на функцию, поскольку аргументы его заключены в скобки:
/* макроопределение с аргументами */ #define SQUARE(x) x*x#define PR(x) printf("x равно %d.\n", x)int main(){ int x = 4; int z; z = SQUARE(x); PR(z); z = SQUARE(2); PR(z); PR(SQUARE(x)); PR(SQUARE(x+2)); PR(100/SQUARE(2)); PR(SQUARE(++x)); return 0;}Всюду, где в нашей программе появляется макроопределение SQUARE(x), оно заменяется на x*x. В отличие от наших прежних примеров, при использовании этого макроопределения мы можем совершенно свободно применять символы, отличные от x. В макроопределении ' x ' замещается символом, использованным в макровызове программы. Поэтому макроопределение SQUARE(2) замещается на 2*2. Таким образом, x действует как аргумент. Однако, аргумент макроопределения не работает - точно так же, как аргумент функции. Вот результаты выполнения программы:
|
|
Первые две строки очевидны. Заметим, что даже внутри двойных кавычек в определении PR переменная замещается соответствующим аргументом. Все аргументы в этом определении замещаются. Рассмотрим третью строку:
PR(SQUARE(x));Она становится следующей строкой:
printf("SQUARE(x) равно %d.\n", SQUARE(x));после первого этапа макрорасширения. Второе SQUARE(x) расширяется, превращаясь в x*x, а первое остается без изменения, потому что теперь оно находится внутри кавычек в операторе программы, и таким образом защищено от дальнейшего расширения. Окончательно строка программы содержит
printf("SQUARE(x) равно %d.\n",x*x);и выводит на печать
SQUARE(x) равно x*x.Если макроопределение включает аргумент с двойными кавычками, то аргумент будет замещаться строкой из макровызова. Но после этого он в дальнейшем не расширяется, даже если строка является еще одним макроопределением. В нашем примере переменная x стала макроопределением SQUARE(x) и осталась им. Вспомним, что x=4. Это позволяет предположить, что SQUARE(x+2) будет равно 6*6 или 36. Но напечатанный результат говорит, что получается число 14. Причина такого результата такова: препроцессор не делает вычислений. Он только замещает строку. Всюду, где наше определение указывает на x, препроцессор подставит строку x+2.
Таким образом,
x*x становится x+2*x+2Если x равно 4, то получается
4+2*4+2=4+8+2=14Вызов функции передает значение аргумента в функцию во время выполнения программы. Макровызов передает строку аргументов в программу до ее компиляции.