Урок 12.2. Опредлеление макрофункций

12.2. Опредлеление макрофункций

В программировании принято называть идентификатор, следующий после
#define макроопределением. В случае, если этот идентификатор встречается в
программе, он называется макровызовом, а замена препроцессором макроопределения
на строку замещения называется макрорасширением.

Если непосредственно
за идентификатором следует открывающая скобка,то препроцессор считает, что в
программе определено макроопределние с аргументамми (его также называют макрофункцией).
Общая форма записи директивы #define:

#define
_идент.1_(_идент.2_,...,_идент.N_) _строка подстановки_

В этом случае _идентификатор2_,...,_идентификаторN_ называются
формальными параметрами макроопределения. Использование макроопределений очень просто
и очень похоже на вызов функции. Чтобы использовать макроопределение нужно
указать его имя (_идентификатор1_), а затем в скобках - фактические параметры.
Встретив где-либо в программе имя макроопределения с последующим списком
фактических параметров, заключенным в скобки, (макровызов), препроцессор
заменяет его на _строку подстановки_. При этом все вхождения формальных
параметров в _строку подстановки_ заменяются соответствующими фактическими
параметрами, исключая те, которые в _строке подстановки_ заключены в кавычки.
После этого, как и в случае макроопределения без параметров, строка вновь
просматривается, и если в ней есть другие макроопределения, они также
соответствующим образом заменяются (расширяются). И в этом случае, естественно,
строки, заключенные в двойные кавычки считаются "защищенными". Пример:

#define VOL(a,b,c) a*b*c

#define PRNT(x) printf("x равен %d \n",x)

main()

{

int x,y,z,v;

x=3;y=17;z=15;

v=VOL(x,y,z);

PRNT(v);

}

После завершения работы препроцессора эта программа будет иметь вид:

main()

{

int x,y,z,v;

x=3;y=17;z=15;

v=x*y*z;

printf("x равен %d \n",v);

}

При макрорасширении строки PRNT(v) формальный параметр заменился на фактический
только во втором случае, так как в первом случае он "защищен"
кавычками.

Обратите внимание на строку v=VOL(x,y,z);
. После расширения она "превратилась" в строку v=x*y*z; . Следовательно, как мы уже отмечали,
препроцессор не выполняет вычислений, а только замещает строку. Таким образом,
если бы мы написали v=VOL(x+3,y,z+12);
, мы бы получили v=x+3*y*z+12; . Поскольку приоритет операции умножения
выше, чем операции сложения, сначала будет выполнено умножение, а потом
сложение. Но очевидно ,что макрофункция VOL написана для перемножения своих аргументов. Для того, чтобы избежать
подобных ситуаций, следует каждый формальный параметр макроопределения в строке
подстановки заключать в скобки:

#define VOL(a,b,c) (a)*(b)*(c)

Тогда если мы запишем
v=VOL(x+3,y,z+12); , то после работы препрцессора получим
v=(x+3)*(y)*(z+12); и при работе
программы вычисления будут выполняться правильно. Кроме того, рекомендуется всю
стрроку подстановки заключать в скобки во избежание ошибок, подобных
слдедующей: h=15/VOL(x+3,y,z+12); . После макрорасширения эта строка
преобразуется в h=15/(x+3)*(y)*(z+12); . Так как вычисления выполняются слева
направо, то сначала выполнится деление, а затем частное будет умножено на y и
на (z+12), хотя ясно, что сначала имелось ввиду
выполнить умножение, а затем - деление. Заключив строку подстановки в скобки,
мы сможем избежать и этой ошибки:

#define VOL(a,b,c) ((a)*(b)*(c))

В этом случае h=15/VOL(x+3,y,z+12); после расширения будет иметь вид h=15/((x+3)*(y)*(z+12)); и вычисления будут производиться правильно.

На этом примере видно очень важное отличие макроопределений от функций:

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

(поэтому программист,
используя макроопределения не должен заботиться о совпадении типов формальных и
фактических параметров. Ведь передается не значение, а строка.) Символ #,
помещенный перед формальным параметром макроопределения в строке подстановки,
указывает на необходимость преобразования его в строку. При макрорасширении
#_формальный параметр_ заменяется на "фактический параметр".

Если в приведенном выше примере программы вместо

#define PRNT(x) printf("x равен %d \n",x)

написать

#define
PRNT(x) printf(#x"равен %d \n",x) ,

то встретив в программе PRNT(v), препроцессор заменит его на printf("v""равен
%d\n",v).

Довольно часто перед программистами встает вопрос: что использовать -
макроопределение или функцию? Здесь можно привести следующие соображения:

использование макроопределений увеличивает объемпрограммы и чревато
побочными эффектами;использование
функций увеличивает время выполнения

программы (бывает,
что весьма существенно) и,кроме

того, при
использовании функций нужно заботиться о

совпадении типов
формальных и фактических параметров,

чего не нужно делать при использовании макроопределений

рассказать друзьям и получить подарок

Оставить комментарий

Ваш email не будет опубликован. Обязательные поля отмечены *

Вы можете использовать это HTMLтеги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Translate Переводчик

Подписка на новости

SmartResponder.ru
Ваш e-mail: *
Ваше имя: *

Хостинг для Wordpress сайтов