Использование аргументов с #define

Во избежание ошибок при вычислении выражений параметры макроопределения необходимо заключать в скобки.

#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 действует как аргумент. Однако, аргумент макроопределения не работает - точно так же, как аргумент функции. Вот результаты выполнения программы:

z равно 16.z равно 4.SQUARE(x) равно 16.SQUARE(x+2) равно 14. 100/SQUARE(2) равно 100.SQUARE(++x) равно 30.

Первые две строки очевидны. Заметим, что даже внутри двойных кавычек в определении 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

Вызов функции передает значение аргумента в функцию во время выполнения программы. Макровызов передает строку аргументов в программу до ее компиляции.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: