sem09 - препроцессор_ gcc (1114923)
Текст из файла
1Занятие №91.1 ПрепроцессорПрепроцессирование — это специальный просмотр исходного файла на языке Си, в ходекоторого выполняются специальные директивы (директивы препроцессора) и производитсямакроподстановка в тексте программы. Результатом работы препроцессора является текстовый файл, который далее попадает на вход основной стадии трансляции.Каждая директива препроцессора должна быть записана в отдельной строке файла.
Принеобходимости директива препроцессора может быть продолжена на следующую строку, если последним символом строки записать символ «обратной косой черты» \. Отличительным признаком директивы препроцессора является символ #, который должен быть первымнепробельным символом в строке.1.1.1 Директивы #define, #undefДиректива препроцессора #define позволяет задавать новые макроопределения, которые могут быть как с параметрами, так и без параметров. Определение макроса без параметров выглядит следующим образом:#define <name> <text>Здесь <name> — это имя макроса, которое должно быть идентификатором в смысле языка Си, то есть начинаться с латинской буквы или подчёркивания, за которой идут ноль илиболее латинских букв, символов подчёркивания или цифр.
Как и в языке Си, при сравненииимён учитывается регистр букв. Определяемое имя не должно быть уже определённым макросом, в противном случае выдаётся ошибка. <text> — это произвольный текст, то естьпоследовательность допустимых лексических единиц языка Си. Если в тексте встречаютсякомментарии, каждый комментарий заменяется на один символ пробела.Например,#define M_PI 3.14159265358979323846определяет макрос M_PI, а#define while /* do substitution */ doопределяет макрос while, который раскрывается в do. Поскольку макроподстановкапроисходит до синтаксического анализа программы, такое макроопределение приведёт к тому, что все ключевые слова while будут заменены на ключевые слова do.Определение макроса с параметрами выглядит следующим образом:#define <name>( <params> ) <text>Открывающая скобка не должна быть отделена пробельными символами от имени макроса.Если в списке параметров или в тексте встречаются комментарии, каждый комментарий заменяется на один символ пробела.
Параметры макроопределения — это список идентификаторов, разделённых запятыми. Параметры могут использоваться в тексте макроопределения,тогда при макроподстановке на месте имени параметра будет стоять текст соответствующегофактического параметра макроса.Например,#define swap(a,b) (a ^= b, b ^= a, a ^= b)1это возможный вариант макроса, который меняет местами две переменных какого-либоодного целого типа, а макрос#define CHECK(x) if (x < 0) { fprintf(stderr, "x < 0"); exit(1); }может использоваться при контроле допустимых значений в какой-либо функции.Текст макроопределения может использовать другие макросы.
В момент определения макросы никак не раскрываются, их полное раскрытие откладывается на момент использования макроса. Например, следующий фрагмент программы#define A B + 1#define B 2x = A + 2;присвоит переменной x значение 5.В тексте макроопределения могут использоваться две специальных операции: превращения аргумента в строку и конкатенации. Преобразование аргумента в строку записываетсякак #<param>, где <param> — это имя параметра макроса. Преобразование можно трактовать как заключение значения параметра в кавычки, а если кавычки присутствуют в текстезначения параметра, они экранируются с помощью символа \. Например, если дано макроопределение#define tostr(a) #aвызов tostr(a > b) раскроется в "a > b", а вызов tostr(puts("hello")) раскроется в "puts(\"hello\")".Операция склейки записывается как <arg1>##<arg2>, где аргументы операции —произвольные лексические единицы. Результатом склейки будет одна новая лексическаяединица.
Например, если дано макроопределение#define glue(a,b) a##bзапись glue(a,2) будет раскрыта в идентификатор a2, запись glue(d,o) будет раскрыта в ключевое слово do, а запись glue(+,+) будет раскрыта в знак операции инкремента ++.Транслятор языка Си предопределяет несколько макросов. Макрос __LINE__ всегдараскрывается в номер строки текста, в которой он используется, макрос __FILE__ раскрывается в строку, которая содержит имя просматриваемого в данный момент времени препроцессором файла, а макрос __DATE__ раскрывается в строку, которая содержит время компиляции.
Кроме того, каждый транслятор определяет дополнительные макросы, по которымможно узнать версию транслятора, операционную систему, тип процессора и пр. Например,макрос __GNUC__ раскрывается в номер версии компилятора gcc, если для компиляции используется он. Макрос __linux__ равен 1, если компиляция ведётся в системе Linux, и т.д.Директива препроцессора #undef <name> сбрасывает определение макроса с именем<name>. С этого момента макрос становится неопределённым и может использоваться, например, как обыкновенный идентификатор. Если данное имя не было определено как макрос,директива не делает ничего.1.1.2 Макроподстановки в тексте программыЕсли препроцессор находит в тексте программы идентификатор, который является именем ранее определённого макроса, препроцессор выполняет макроподстановку.
Препроцессор не выполняет макроподстановку в комментариях, символьных строках и символьныхконстантах.2Если макрос был определён как макрос без параметров, идентификатор заменяется натекст макроопределения, причём справа и слева от подставляемого текста добавляется поодному символу пробела.
Например, если макрос M_PI определён, как описано выше, текстM_PI(10) будет раскрыт в 3.14159265358979323846 (10).Если макрос был определён как макрос с параметрами, а в тексте программы сразу после идентификатора не следует символ открывающей скобки, идентификатор не изменяетсяи макроподстановки не происходит. Например, если в тексте программы используется идентификатор glue сам по себе, он не изменится в результате препроцессирования.Если в тексте программы сразу после идентификатора следует открывающая скобка,препроцессор проверяет совпадение количества параметров в макроопределении и макровызове.
В случае несовпадения выдаётся сообщение об ошибке. Далее вместо текста макровызова подставляется текст макроопределения, в котором формальные параметры замененына текст, который находится в соответствующих фактических параметрах.Препроцессор не выполняет рекурсивной макроподстановки. Если при обработкекакого-либо макровызова произвести очередное макрорасширение означало бы войти врекурсию, препроцессор оставляет макровызов без изменений. Например, пусть даны двамакроопределения#define X Y + 1#define Y X + 1В этом случае текст X раскроется в X + 1 + 1, а текст Y раскроется в Y + 1 + 1.Если в тексте-параметре макровызова используются макровызовы, макроподстановки втексте параметра выполняются до того, как текст параметра будет подставлен вместо соответствующего формального параметра. Например, если дано макроопределение#define S(a,b)текст S(a,S(b,c)) раскроется в a + b + c.1.1.3 Использование макроопределенийПоскольку препроцессирование производится до синтаксического анализа программы иможет произвольным образом менять лексическую и синтаксическую структуру программы,при использовании макросов нужно учитывать следующие детали.Лексическая вложенность.
Макроопределения не подчиняются правилам лексическойвложенности языка Си. То есть, если в тексте программы определяется макрос с именемname, ниже по тексту он может только использоваться, либо переопределяться с помощьюдирективы препроцессора #define, либо сбрасываться с помощью директивы препроцессора #undef. После директивы #undef имя становится доступным для полноценного использования в программе. Например, следующий фрагмент программы даст при компиляциисинтаксическую ошибку:#include <stdio.h>int main(void){int NULL = 0;return 0;}Имя NULL определяется в файле <stdio.h> как макрос.Приоритеты операций. Приоритеты операций в выражениях после макрорасширениймогут не совпасть с ожидаемым порядком вычисления операций. Например, пусть макрос Sопределён как3#define S(a,b) a + bПредположим, что он используется как S(1<<2,3).
Можно было бы ожидать, что результат вычисления такого выражения равен 7, но после макроподстановки получается выражение 1<<2 + 3, значение которого — 32. Поэтому в подобных случаях использованиепараметров в тексте макроопределения нужно заключать в скобки.Даже модифицированное макроопределение#define S(a,b) (a) + (b)не устраняет всех проблем. Рассмотрим выражение S(1,2)*3. Можно было бы ожидать, что его значение равно 9, однако после макроподстановки получается выражение(1)+(2)*3, значение которого равно 7. Поэтому в подобных случаях и весь текст макроопределения нужно заключать в скобки.Итак, правильное макроопределение должно выглядеть следующим образом#define S(a,b) ((a)+(b))Побочные эффекты.
Если один и тот же параметр макроса используется в его теленесколько раз, использование в качестве параметра макроса выражения с побочным эффектом может привести к неожиданным результатам. Например, пусть имеется макроопределение, которое вычисляет максимальное из двух чисел:#define max(a,b) ((a)>=(b)?(a):(b))Предположим, что значение переменной x равно 6, а значение переменной y равно 7. Тогда значение выражения max(++x,y) равно 8! В самом деле, выражение раскроется следующим образом: ((++x)>=(y)?(++x):(y)), и поскольку ++x даёт результат 7, и это жезначение будет присвоено переменной x, условие будет выполнено, поэтому выражение ++xбудет вычислено ещё один раз.Поскольку избежать повторного вычисления аргументов с побочным эффектом невозможно, макросы, которые используют свои аргументы несколько раз, должны быть задокументированы, чтобы предупредить возможные ошибки при их использовании.Границы операторов.
Характеристики
Тип файла PDF
PDF-формат наиболее широко используется для просмотра любого типа файлов на любом устройстве. В него можно сохранить документ, таблицы, презентацию, текст, чертежи, вычисления, графики и всё остальное, что можно показать на экране любого устройства. Именно его лучше всего использовать для печати.
Например, если Вам нужно распечатать чертёж из автокада, Вы сохраните чертёж на флешку, но будет ли автокад в пункте печати? А если будет, то нужная версия с нужными библиотеками? Именно для этого и нужен формат PDF - в нём точно будет показано верно вне зависимости от того, в какой программе создали PDF-файл и есть ли нужная программа для его просмотра.