Препроцессор языка Си (1114933)
Текст из файла
А.А. ВылитокПрепроцессор языка СиПрепроцессор языка Си – это обработчик макросов, аналог макрогенератора вмакроассемблере. Он просматривает текст программы, написанной на Си, до того, как онабудет обработана компилятором. Текст хранится в символьном файле, разбитом на строкисимволами-маркерами «конец строки».В некоторых системах препроцессор может быть совмещен с процессомкомпиляции, в других может быть отдельной программой, результатом которой являетсяфайл без макросов на «чистом» Си.Управляется препроцессор директивами. Директивой является строка,начинающаяся символом #.
До и после # могут быть пробелы. За символом # должноследовать имя директивы.Строки препроцессора распознаются до генерации макрорасширений. Поэтому,если макрос сгенерирует новую директиву препроцессора, она не будет выполнена.Если в строке исходного файла содержится символ \ непосредственно передмаркером конца строки, то этот символ выбрасывается вместе с маркером и две соседниестроки склеиваются в одну строку. Это происходит до обработки директив препроцессора.Лексемами для препроцессора являются все лексемы языка Си и, кроме того,последовательности символов, задающие имена файлов, например, в директиве #include.Макроопределения без параметровСтрока вида# define имя последовательность_лексемопределяет макрос имя с телом последовательность_лексем (последовательность можетбыть пустой).
Тело макроса начинается сразу за его именем (никаких знаков равенства ит.п. перед телом нет). Когда в тексте программы встречается имя макроса, оно заменяетсяего телом (макроподстановка).Примеры#define#define#define#define#defineEOF -1EOT ’\004’BUF_SIZE 1024ER_MESSAGE ”>>error %d:%s\n”forever for(;;) /* бесконечный цикл */#define NUMBER_OF_FILES = 7 /* опасно! но лексически корректно,телом будет =7*/При таком определении, фрагмент while(n!=NUMBER_OF_FILES)преобразован к ошибочному фрагменту while (n!==7).будетМакроопределения с параметрамиСтрока вида# define имя( список_идентификаторов ) последовательность_лексем ,где между именем и открывающей скобкой нет ни одного пробельного символа, являетсямакроопределением с параметрами, задаваемыми списком идентификаторов (списокможет быть пустым).
Параметры в списке перечисляются через запятую. Числофактических параметров при вызове макроса должно совпадать с числом формальныхпараметров. При макрорасширении каждое вхождение формального параметра в теломакроса заменяется на соответствующий фактический параметр.Примеры[1]#define max(X,Y)((X) > (Y) ? (X) : (Y))Фрагмент a=max(b+c, f(d,e)) будет заменен наa=((b+c) > (f(d,e)) ? (b+c) : (f(d,e)))Вызов макроса похож на вызов функции, причем он подходит для аргументовлюбого типа, так что не нужно писать разные функции max для данных разных типов.Однако в отличие от вызова функции, одно из выражений, задающих фактическиепараметры в данном примере, вычисляется дважды, что может привести к неожиданнымпоследствиям в случае использования побочных эффектов в этих выражениях:max( x++, y++);a=(( x++) > (y++) ? (x++) : (y++)); — одиниз аргументов будет увеличен на 1, другой на 2.[2]Формальные параметры, вместо которых будут подставляться выражения, в телемакроса следует заключать в скобки, чтобы обеспечить нужный порядок вычислений.Вот пример потенциально ошибочного определения квадрата числа:#define square(x) x*x/* может быть ошибка при использовании */Длявызова square(y+1) получим расширение y+1*y+1, не соответствующееквадрату аргумента.[3]Макрос getchar имеет пустой список параметров:#define getchar() getc(stdin)При вызове этого макроса используется пустой список аргументов:while (( c=getchar() != EOF) …[4]Определение функциональных макросов для использования их в качествеоператоров-выражений, может приводить к ошибкам.
Например:#define swap(a,b) {unsigned long _temp=a; a=b; b=_temp;}Попробуем использовать данный макрос в следующем контексте:if (x>y) swap(x,y); /*ошибка*/else x=y;Макрорасширение будет содержать лишнюю точку с запятой перед else:if (x>y) {unsigned long _temp=x; x=y; y=_temp;}; /*ошибка*/else x=y;В данной ситуации можно использовать цикл do-while c единственной итерацией.#define swap(a,b) do { unsigned long _temp=a; a=b; b=_temp;} \while(0)Так как синтаксис цикла do-while требует точку с запятой после выражения, в результатемакроподстановки получим безошибочный фрагмент:if (x>y) do {unsigned long _temp=x; x=y; y=_temp;} while(0);else x=y;[5]В результате макроподстановки может появиться новый вызов макроса, который всвою очередь заменяется макрорасширением.
Рассмотрим пример:#define sum(x,y) add(y,x)#define add(x,y) ((x)+(y))Вызов sum(sum(a,b),c) приведет к следующей последовательностимакрорасширений:sum(sum(a,b),c) add(c, sum(a,b)) ((c)+(sum(a,b)) ((c)+(add(b,a)) ((c)+(((b)+(a))))[6]С помощью макросов можно переопределять функции. Следующий макроспереопределяет извлечение квадратного корня с целью особой обработки отрицательныхаргументов:#define sqrt(x) ((x)<0 ? sqrt(-(x)) : sqrt(x))Отмена определения макросаДиректива вида#undef имязаставляет препроцессор «забыть» определение макроса имя. Использование этойдирективы для неопределенного имени не считается ошибкой.
После отмены определенияимя может быть заново определено с помощью директивы #define. Чтобы избежатьповторного переопределения, можно использовать директиву условной компиляции#ifndef и парную ей конструкцию #endif:#ifndef SIZE#define SIZE 1000#endifВключение файловДиректива препроцессора вида#include < имя файла >#includeили”имя файла”подставляет весь текст, который находится в указанном файле, на место директивы. Имяфайла записывается в формате, зависящем от реализации. Порядок поиска указанногофайла также определяется реализацией.
Основная цель использования формы вида ”…”состоит в доступе к заголовочным файлам, написанным самим программистом, в то времякак форма < … > используется для ссылки на стандартные файлы реализации.Условная компиляцияС помощью директив условной компиляции препроцессор включает в текстпрограммы или исключает из него строки исходного текста в зависимости от истинностиусловия. В качестве условия используется константное выражение. Нулевое значениеозначает «ложь», ненулевое – «истину». Константное выражение должно бытьцелочисленным и не может содержать в себе перечислимых констант, преобразованийтипа и операторов sizeof.БНФ для условной конструкции препроцессора выглядит так: условная конструкция ::= if-строка elif-части [#else текст] #endif if-строка::=#if константное выражение |#ifdef идентификатор | #ifndef идентификатор elif-части::= { #elif константное выражение текст }Описанная выше конструкция обрабатывается так, что константные выражения вif- и elif-строках вычисляются по порядку, пока не будет обнаружено истинноевыражение.
Текст, следующий за директивой с истинным значением, обрабатываетсяобычным образом, остальные части игнорируются. Если все выражения ложны иприсутствует строка #else, то следующий за ней текст обрабатывается обычнымобразом. Директивы #ifdef и #ifndef позволяют включать текст в случае, еслиследующий за директивой идентификатор определен или не определен ( для #ifndef).Вместо #ifdef и #ifndef можно использовать #if с выражениями defined идентификатор и !defined идентификатор соответственно. Например, чтобызастраховаться от повторного включения заголовочного файла hdr.h, его можно оформитьследующим образом:#if !defined(HDR)#define HDR/* содержимое hdr.h */…#endifПреобразование лексем в строкиЛексема #, которая появляется внутри макроопределения перед параметром,означает что параметр (вместе со знаком # перед ним) заменяется на подставляемыйвместо параметра текст, заключенный в двойные кавычки.Склеивание лексем в макрорасширенияхСклеивание лексем с целью формирования новых лексем осуществляется спомощью операции ##.
Две лексемы, разделенные операцией ##, склеиваются в однулексему.#define TEMP(i) temp ## iTEMP(1)= TEMP(2+ m)+ y;После обработки препроцессором это выражение будет иметь следующий вид:temp1 = temp2 + m + y;.
Характеристики
Тип файла PDF
PDF-формат наиболее широко используется для просмотра любого типа файлов на любом устройстве. В него можно сохранить документ, таблицы, презентацию, текст, чертежи, вычисления, графики и всё остальное, что можно показать на экране любого устройства. Именно его лучше всего использовать для печати.
Например, если Вам нужно распечатать чертёж из автокада, Вы сохраните чертёж на флешку, но будет ли автокад в пункте печати? А если будет, то нужная версия с нужными библиотеками? Именно для этого и нужен формат PDF - в нём точно будет показано верно вне зависимости от того, в какой программе создали PDF-файл и есть ли нужная программа для его просмотра.