Информатика -продвинутый курс

       

ДИРЕКТИВЫ ПРЕПРОЦЕССОРА


Препроцессор - это программа, которая производит некоторые, иногда весьма значительные, манипуляции с первоначальным текстом программы перед тем, как он подвергается трансляции.

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

Операторы препроцессора могут появляться в любом месте программы и их действие распространяется на весь исходный файл.

Весьма часто используют следующие операторы препроцессора:

#include

#define

Более специфичными являются директивы #pragma, #if, #error и др.

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

Например, чрезвычайно часто в начале программы на языке Си встречается препроцессорная конструкция

#include <stdio.h>

Когда исходный текст программы обрабатывается препроцессором, на место этой инструкции ставится содержимое расположенного в некоем стандартном месте файла stdio.h, содержащего макроопределения и объявления данных, необходимых для работы функций из стандартной библиотеки ввода-вывода. Для использования различных математических функций необходимо подключать файл описаний math.h. Функции, оперирующие со строками, описаны в файле string.h, функции общего назначения - в stdlib.h, функции даты и времени - в time.h, диагностика - в assert, h и т.д.

Директива #define позволяет дать в программе макроопределения (или задать макросы). Оператор макроопределения имеет вид

#define <макроимя> <строка лексем> или



#define <макроимя(<список параметров>)> <строка лексем>

Макроимя - это идентификатор. Строка лексем - это последовательность лексем от Макроимени до конца строки. Точка с запятой в конце макроопределения не ставится.

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


Например, прочитав определения

#defmePI3.14159

#defineE2.711828

препроцессор заменит в программе все имена PI и Е на соответствующие числовые константы.

Препроцессор языка Си позволяет переопределять не только константы, но и целые программные конструкции. Например, можно написать определение

#define forever for(;;)

и затем всюду писать бесконечные циклы в виде forever

Определение макроимени с параметрами имеет некоторую специфику. Список параметров макроимени - это список идентификаторов, разделенных запятыми. Следующая после списка параметров строка лексем также может содержать эти параметры, которые при макровызове будут заменены на соответствующие аргументы.

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

В следующих программах иллюстрируются некоторые применения операторов препроцессора.

Пример 1: найти большее из двух чисел.

Программа 110

#include<stdio.h>

#define MAX(X,Y) ((X)>(Y) ? (X) : (Y))

main()

{

int x,y;

scanf ("%d %d", &x, &y); printf ("%d", MAX(x, y) );

)

Результат работы программы:

3                     5

5

Пример 2.

Программа 111

#include<stdio.h>

#define S (x) x*x

#define P(x) printf("x равен

%d.\n",x)

main()

{

int x=4;

int z ;

z = S(x); P(z); z = 3(2);

P(z);

P(S(x));

P(S(x+2));

P(100/S(2));

P(S(++x)) ;

}

Результат работы программы:

x равен 16.

x равен 4.

x равен 16.

x равен 14.

x равен 100.

x равен 30.

Оператор препроцессора #pragma позволяет записывать самые различные указания компилятору (зависящие от конкретного компилятора). Например, следующие два предложения препроцессора

#pragma recursive

#pragma nonrec

устанавливают режим всех функций программы по умолчанию рекурсивным или нерекурсивным. Указание препроцессора

#pragma optimize time

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


Содержание раздела