Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
12
Добавлен:
17.04.2015
Размер:
34.77 Кб
Скачать

8. Макрокоманды или макросы.

Как известно, макрокоманды предоставляют способ определения констант,которые до начала компиляции заменяются препроцессором их значениями по всей программе. Кроме того, макрокоманды позволяют создавать операции, которые подобны по своему использо-ванию функциям, и могут работать с параметрами (значениями, которые передаются в макрокоманду).

Во второй синтаксической форме в директиве define имеется список формальных параметров, который может содержать один или несколько идентификаторов, разделенных запятыми. Формальные параметры в тексте макроопределения отмечают позиции, на которые должны быть подставлены фактические аргументы макровызова. Каждый формальный параметр может появиться в тексте макроопределения несколько раз. При макровызове вслед за идентификатором записывается список фактических аргументов, количество которых должно совпадать с количеством формальных параметров.

Пример макроопределения:

#define SQUARE(X) (X)*(X)

Отметим, что скобки необходимы (как и в предыдущем примере) для обеспечения правильного порядка действий.

Теперь при появлении в программе выражения Z=SQUARE(2); переменная Z получит значение, равное 4.

9. Примеры создания макрос.

1.Следующей макрокомандой SUM возвращается сумма двух передаваемых ей значений:

#define SUM(x, у) ((х) + (у))

В следующей программе SHOW_SUM.C макрокоманда SUM используется для сложения разных значений:

#include

#define SUM(x, у) ((х) + (у))

void main(void)

{

printf("Сложение 3 + 5 = %d\n", SUM(3, 5)) ;

printf("Сложение 3.4 + 3.1 = %f\n", SUM(3.4, 3.1));

printf("Сложение -100 + 1000 = %d\n", SUM(-100, 1000));

}

В определении макрокоманды SUM x и у являются параметрами. Когда два значения передаются в макрокоманду, например SUM (3,5), препроцессор подставляет их вместо параметров в теле макрокоманды. В программе SHOW_SUM.C в результате подстановок препроцессора генерируется следующий код:

printf("Сложение 3 + 5 = %d\n", (3) + (5) ) ;

printf("Сложение 3.4 + 3.1 = %f\n", (3.4) + (3.1));

printf("Сложение -100 + 1000 = %d\n", (-100) + (1000));

Об использовании символа ";" в определениях макрокоманд

Если рассмотреть определение макрокоманды SUM, приведенное ниже, то можно отметить, что в макроопределении не содержится символ "точка с запятой" (;):

#define SUM(x, у) ((x) + (у))

Если включить точку с запятой в макроопределение, то этот символ будет подставляться препроцессором в каждом появлении макрокоманды в программе. Предположим, что в конце макроопределения SUM указывается точка с запятой:

#define SUM(x, у) ((х) + (у));

В процессе расширения вызовов макрокоманды символ ";" будет включаться следующим образом:

printf("Сложение 3 + 5 = %d\n", (3) + (5););

printf("Сложение 3.4 + 3.1 = %f\n", (3.4) + (3.1););

printf("Сложение -100 + 1000 = %d\n", (-100) + (1000););

Поскольку в этом случае точка с запятой оказывается внутри оператора printf (отмечая конец оператора), компилятор выдаст ошибку. Примечание: Следует избегать включения точки с запятой в определение макрокоманды, даже если это кажется очень удобным.

2.Создание макрокоманд MIN и МАХ

Посредством следующих макрокоманд MIN и МАХ возвращается минимальное и максимальное из двух значений:

#define MIN(x, у) (((х) < (у)) ? (х) : (у))

#define МАХ(х, у) (((х) > (у)) ? (х) : (у))

В следующей программе MINMAX.C демонстрируется использование этих двух макрокоманд:

#include

#include

void main (void)

{

printf("Минимум из 3 и 5 равен %d\n", MIN (3, 5));

printf("Максимум из 3.4 и 3.1 равен %f\n", MAX (3.4, 3.1));

printf("Минимум из -100 и 1000 равен %d\n", MIN (-100, 1000));

}

В данном случае в результате подстановок препроцессора генерируется следующее:

printf("Минимум из 3 и 5 равен %d\n",

(((3) < (5)) ? (3) : (5))) ;

printf("Максимум иэ 3.4 и 3.1 равен %f\n",

(((3.4) > (3.1)) ? (3.4) : (3.1))) ;

printf("Минимум иа -100 и 1000 равен %d\n",

(((-100) < (1000)) ? (-100): (1000)));

  1. Создание макрокоманд SQUARE и CUBE

Как известно, Си позволяет определять макрокоманды и передавать им значения при вызове. Следующие две макрокоманды SQUARE и CUBE в качестве результата возвращают значение аргумента, возведенное во вторую (х * х) и третью (х * х * х) степень соответственно:

#define SQUARE(х) ((х) * (х))

#define CUBE(х) ((х) * (х) * (х))

В следующей программе SQR_CUBE.C показано использование макрокоманд SQUARE и CUBE:

#include

#define SQUARE(x) ((x) * (x))

#define CUBE(x) ( (x) * (x) * (x) )

void main(void)

{

printf("2 в квадрате равно %d\n", SQUARE(2));

printf("100 в кубе равно %f\n", CUBE(100.0));

}

В данном случае в результате подстановок препроцессора генерируется:

printf("2 в квадрате равно %d\n ", (2) * (2));

printf("100 в кубе равно %f\n ", (100.0) * (100.0) * (100.0));

Примечание: Для того чтобы избежать переполнения в макрокоманде CUBE, в программе используется значение с плавающей точкой 100.0.

Об использовании пробелов в определениях макрокоманд

При определении макрокоманд, работающих с параметрами, нужно быть внимательным в отношении символов "пробел", используемых в макроопределении. Не следует помещать пробел между именем макрокоманды и ее параметрами. Например, рассмотрим следующее определение макрокоманды SQUARE:

#define SQUARE (х) ((х) * (x))

При обработке программы препроцессором пробел между именем макрокоманды и параметрами приводит к тому, что каждое появление имени SQUARE должно быть заменено на (х) ((х) * (х)). В большинстве случаев такая подстановка приводит к сообщениям об ошибках или предупреждающим сообщениям. Для того чтобы лучше понять механизм подстановки, рекомендуем проделать эксперимент с программой SQR_CUBE.C, представленной в С 157, помещая пробел после имени каждой макрокоманды.

Использование скобок в макрокомандах

В предыдущих примерах демонстрировались макрокоманды, которым передавались значения (параметры). Если внимательно рассмотреть каждое из определений таких макрокоманд, можно отметить, что параметры заключены в скобки:

#define SUM(x, у) ((х) + (у))

#define SQUARE(х) ((х) * (х))

#define CUBE(х) ((х) * (х) * (х))

#define MIN(x, у) (((х) < (у)) ? (х) : (у))

#define МАХ(х, у) (((х) > (у)) ? (х) : (у))

Причиной заключения параметров в скобки является возможность передачи выражений в качестве параметров. Например, рассмотрим следующий оператор:

result = SQUARE(3 + 5) ;

Оператор должен присвоить переменной result значение 64 (8*8). Предположим, например, что SQUARE определена следующим образом:

#define SQUARE(х) (х * х)

Тогда в результате подстановки для х выражения 3+5 получится следующее:

result = (3 + 5 * 3 + 5) ;

В силу установленного в языке Си приоритета операторов последнее выражение будет вычисляться следующим образом:

result=(3+5*3+5);

=(3+15+5) ;

=23;

С помощью заключения каждого параметра в скобки гарантируется корректное вычисление выражения:

result =SQUARE(3 + 5) ;

=((3+5) * (3 + 5)) ;

=((8) * (8));

=(64);

=64;

Примечание: Следует придерживаться строгого правила: заключать параметры макрокоманд в скобки.

Макрокоманды не имеют типа

Известно, что Си позволяет передавать параметры в функции точно так же, как значения передаются макрокомандам. Если функция выполняет некоторую операцию и возвращает результат, то в определении функции должен быть указан тип результата (такой как int, float и т.д.). Например, следующая функция add_values выполняет сложение двух целых значений и возвращает результат типа int:

int add_values(int x, int у)

{

return(x + у) ;

}

Функция add_yalues может быть использована в программе только для сложения значений типа int. Если с помощью этой функции попытаться сложить два значения с плавающей точкой, то произойдет ошибка. С другой стороны, видно, что макрокоманды позволяют работать со значениями любого типа. Созданная ранее макрокоманда SUM, например, поддерживает значения типа int и float:

printf("Сложение 3 + 5 = %d\n", SUM(3, 5)) ;

printf("Сложение 3.4 + 3.1 = %f\n", SUM(3.4, 3.1));

При использовании макрокоманды для простых арифметических операций устраняется необходимость дублирования функций из-за необходимости работы со значениями различных типов. Однако, как станет ясно из обсуждения в разделе "Функции", имеются и другие соображения, позволяющие решить, что именно является более подходящим - макрокоманды или функции.

4.Макрос вычисления модуля .

#define absolute_value( x ) ( ((x) < 0) ? -(x) : (x) )

...

int num = -1;

while( absolute_value( num ) ) {

...

}

5. Макрос вычисления цикла.

#define count_up( v, low, high ) \

for( (v) = (low); (v) <= (high); (v)++ )

...

int i;

count_up( i, 1, 20 ) {

printf( "i is %d\n", i );

}

В предшествующих советах были представлены макрокоманды, константы и различные препроцессорные директивы. Одним из лучших способов обучения приемам использования этих возможностей является изучение примеров их использования, предлагаемых самим компилятором. Объявления макрокоманд и констант, предлагаемых пользователю компилятором Си, содержатся в заголовочных файлах, которые находятся в поддиректории компилятора INCLUDE. Кроме того, во многих заголовочных файлах используются различные препроцессорные директивы. Изучая различные заголовочные файлы, можно познакомиться со многими способами усовершенствования своих программ, используя преимущества более полного применения возможностей препроцессора.