8.5. Препроцессор

 

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

Директивы препроцессора начинаются знаком # перед которым в строке могут быть пробельные символы.

 

Включающие директивы

 

Имеют вид

 

#include <name>

или

#includename

 

Интерпретация директивы #includeприводит к включению в месте ее появления содержимого файла name. Если имя файла заключено в угловые скобки, то поиск файла ограничивается каталогом файлов, определенным с помощью компилятора. Если имя заключено в кавычки, то предварительно проводится его поиск в текущем файле. Если указано полное имя то поиск не производится, а сразу включается содержимое указанного файла.

Чаще всего эта директива используется для включения стандартных файлов. Например, функции ввода-вывода находятся в файле stdio.h.

Пример

Пусть в файле eva.txt содержится текст

{ printf(“hi”);

то программа

#include <stdio.h>

voidmain ()

#includeeva.txt

}

будет выводить на экран hi

 

Определяющие директивы

 

Макросредства позволяют поставить в соответствие идентификатору текстовую строку; все последующие появления в тексте этого идентификатора заменяются соответствующей строкой. Макроопределения препроцессора имеют 2 вида

простую

#define идентификатор строка-замены

или параметризованную

#define идентификатор (x1,x2, ..., xn) строка-замены

 

Макроопределение в первой форме обеспечивает замену каждого идентификатора строкой-замены для всех идентификатором расположенных после макроопределения.

#definesize 200

При изменении размера в дальнейшем можно будет поменять только эту директиву.

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

Например, рассмотрим ситуацию, когда константа определена следующим образом

#definee 5+10

а где-то в программе написано выражение е*10. то значение этого выражения будет не 150, как, скорее всего, ожидается, а 5+10*10=105

Макросы могут применяться и для ограниченных изменений в синтаксисе языка.

Например, для схожести программы на си с программой на паскале, можно сделать

#define begin {

#define end }

void main()

begin

...

end

 

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

Пример

#define max(a,b) ((a)>(b)?(a):(b))

void main()

{ int x=5, y=6;

            printf(“%d”,max(x,y));

}

интерпретация приведенной записи приведет к генерации выражения

 

void main()

{ int x=5, y=6;

            printf(“%d”, x>y?x:y));        

}

 

Макроопределения, образованные с помощью директивы define могут быть аннулированы с помощью директивы

#undef

 

Пример 1

Многократное развитие макровызовов

#include <stdio.h>

#define alfa char beta

#define beta c=’d’

void main()

{

         alfa;     /* интерпретация этой записи приведет к записи charc=’d’;*/

         printf(“%c”,c)

}

в результате работы программы выведется символ ‘d

 

 Пример 2

Игнорирование макровызовов в директивах #define

#include <stdio.h>

#define beta c=’d’

#define alfa char beta

#undefbeta

voidmain()

{

         alfa;     /* интерпретация этой записи приведет к записи charbeta;*/

         printf(“%c”,c)

}

В результате компилятор выдаст сообщение об ошибке, так как переменная с не определена.

 

Пример 3

Игнорирование макровызовов в символьных и строчных литералах

#include <stdio.h>

#define  c 4

#define alfa 35

void main()

{

         char a=’c’;  

         printf(“alfa\n%c”,a)

}

в результате напечатается

alfa

c

 

К оглавлению

Назад к разделу "8.4. Циклы"

Вперед к разделу "8.6. Массивы"