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

Сравнение макросов и функций

Макросы можно сравнить с функциями. В определении функции содержаться операторы, которые должны выполниться при вызове функции. В строке замещения макроса содержится текст, который должен быть подставлен в текст программы при вызове макроса.

Общие черты макросов и функций:

  • Начинают выполняться в момент вызова,

  • Принимают параметры и возвращают значение,

  • Вызов выполняется по имени с указанием аргументов,

  • При вызове аргументы ставятся на место параметров.

Отличия макросов от функций:

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

  • Для функции тип аргументов и тип возвращаемого значения фиксированы. Макрос пригоден для об­работки аргументов любого типа, который допустим в выражениях строки замещения. Тип получае­мого значения зависит только от типов аргументов и выражений строки замещения. Например, рассмотренный макросы MAX( ) работает для аргументов любых целых и вещественных ти­пов.

  • Фактические параметры функций могут быть выражениями, которые вычисляются в процессе выполнения программы. Аргументы макровызова не могут быть выражением, содержащим переменные, ранее определенные другой директивой #define.

Использование директивы #define

С помощью директивы #define можно вводить собственные обозначения базовых или производных типов.

Пример:

Директива

#define REAL long double

вводит имя REAL для типа long double. Далее в тек­сте программы можно определять объекты типа long double, используя данное имя:

REAL x, array [6];

Такой прием удобно использовать для присвоения более коротких имен сложным типам данных.

Директиву #define также удобно использовать для сокращенного обозначения оператора печати, в случае, когда в программе требуется часто выводить на эк­ран значение переменной с одним и тем же пояснительным текстом.

Пример:

После записи директивы

#define PN printf ("\n Номер элемента=%d", N);

Последовательность операторов

int N=4;

PN;

выведет на экран текст

Номер элемента=4

Еще одной из областей эффективного применения макросов является адресации элементов многомерных массивов.

Доступ к элементам многомерных массивов в С++ имеет две особенности, которые создают неудобства при работе с ними:

  • при обращении к элементу массива нужно указывать все его индексы,

  • нумерация элементов массивов начинается с нуля.

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

Пример:

#define N 4 // число строк матрицы

#define M 5 // число столбцов матрицы

#define A(i,j) x[M*(i-l) + (j-1)]

#include <stdio.h>

void main ( )

{

/* Определение одномерного массива */

double x[N*M];

int i, j, k;

for (k=0; k < N*M; k++) x[k]=k;

/* Перебор строк */

for (i=1; i<=N; i++) {

printf ("\n Строка %d:", i);

for (j=1; j<=M; j++) printf(" %6.1f", A(i, j)); // перебор элементов строк

}

}

Результат выполнения программы:

Строка 1: 0.0 1.0 2.0 3.0 4.0

Строка 2: 5.0 6.0 7.0 8.0 9.0

Строка 3: 10.0 11.0 12.0 13.0 14.0

Строка 4: 15.0 16.0 17.0 18.0 19.0

В программе создается виртуальный многомерный массив, размерностью N×М (N – число строк, M - число столбцов). Размерность массива задается на этапе пре­процессорной обработки с помощью директивы #define. Для имитации многомерного массива (создания виртуального массива) в программе используется макроопределения и одномерный (реальный) массив x[] размерностью N*M. Таким образом, элементы виртуального многомерного массив будут размешаться в одномерном массиве построчно. Значения элементам массива присваиваются в цикле с параметром k.

На рис. 2.7 приведена схема одномерного массива х[ ] для моделирования виртуального двумерного массива с помощью макоопределений.

Рис. 2.7 – Имитация многомерного массива с помощью одномерного массива и макроопределения.

Для доступа к элементам массива используются макровызо­вы A(i, j). Индекс i соот­ветствует номеру строки многомерного массива и изменяется от 1 до N, а индекс j – номеру столбца и изменяется во внутреннем цикле от 1 до М. A(i,j) является достаточно естественным обо­значениями элементов матрицы, причем нумерация столбцов и строк начинается с 1.

За счет применения макросов выполняются замены параметризо­ванных обозначений A(i, j) на x[5*(i-l)+(j-l)]. Далее действия выполняются над элементами одномерного массива х[ ]. Но т.к. данные преобразования выполняются на этапе препроцессорной обработки можно считать, что осуществляется работа с традиционными для многомерных массивов обозначениями.

Использованный в программе оператор

printf (“% 6.1f”, A (i, j));

после макроподстановок будет иметь вид:

printf (“% 6.1f”, x[5*(i-l)+(j-l)]);

Например

A (1,1) соответствует x[0] - вычислено как x[5(1-1)+(1-1)]

A (1,2) соответствует x[1] – вычислено x[5(1-1)+(2-1)]

A (2,1) соответствует x[5] – вычислено как x[5(2-1)+(1-1)]

A (3,4) соответствует x[13] – вычислено как x[5(3-1)+(1-1)]

Макросы унаследованы из языка С, при написании программ на C++ их следует избегать. Вместо макросов без параметров предпочтительнее использовать const или enum, а вместо параметризованных макросов — встроенные функ­ции или шаблоны.

Директива #undef отменяет действие директивы #define.

Директива #undef имеет следующий формат:

#undef идентификатор

После выполнения директивы идентификатор, ранее определенный директивой #define. для пре­процессора становится неопределенным, и его можно опреде­лять повторно.