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

Лекция № 11 Директива препроцессора #define

Содержание лекции.

    1. Обработка программ в С.

    2. Директивы препроцесора.

    3. Синтаксис директивы define

    4. Определение констант в программе

    5. Подстановка макрокоманд и констант

    6. Выбор имен для констант и макрокоманд

    7. Примеры констант.

    8. Макрокоманды или макросы.

    9. Примеры создания макрос.

    10. Стиль программирования.

    11. Сопоставление макрокоманд и функций

              1. Обработка программ в С.

Программа – это, прежде всего, текст на языке Си++. С помощью компилятора текст преобразуется в исполняемыйфайл – форму, позволяющую компьютеру выполнять программу.

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

Фазы трансляции.

Итак, вот что на самом деле происходит с программой при трансляции:

Сначала запускается так называемый препроцессор языка С. Он делает из текста на языке С ... текст на языке С. Не очень понятно?

Затем этот "второй" текст на С обрабатывается транслятором, и в результате получается текст на ассемблере (ассемблер - это язык низкого уровня, состоящий в сущности из символических эквивалентов машинных команд). Текст на ассемблере уже учитывает специфику вашего компьютера, его систему команд. Но это все еще текстовый файл, файл, который можно читать.

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

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

Системные функции и стандартные функции языка Си++ заранее откомпилированы и хранятся в виде библиотек. Библиотека – это некий архив объектных модулей, с которым удобно компоновать программу.

Основная цель многоэтапной компиляции программ – возможность компоновать программу из многих файлов. Каждый файл представляет собой законченный фрагмент программы, который может ссылаться на функции, переменные или классы, определенные в других файлах. Компоновкаобъединяет фрагменты в одну "самодостаточную" программу, которая содержит все необходимое для выполнения.

      1. Директивы препроцессора.

Директивы препроцессора представляют собой инструкции, записанные в тексте программы на СИ, и выполняемые до трансляции программы. Директивы препроцессора позволяют изменить текст программы, например, заменить некоторые лексемы в тексте, вставить текст из другого файла, запретить трансляцию части текста и т.п. Все директивы препроцессора начинаются со знака #. После директив препроцессора точка с запятой не ставятся.

3. Синтаксис директивыdefine

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

Директива define имеет две синтаксические формы:

#define идентификатор текст

#define идентификатор (список параметров) текст

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

Идентификатор (макрос) в директиве define принято записывать прописными буквами:

#define WIDTH 80

#define LENGTH (WIDTH+10)

Эти директивы изменят в тексте программы каждое слово WIDTH на число 80, а каждое слово LENGTH на выражение (80+10) вместе с окружающими его скобками.

Скобки, содержащиеся в макроопределении, позволяют избежать недоразумений, связанных с порядком выполнения операций. Так, при отсутствии скобок выражение t=LENGTH*7 будет преобразовано в выражение t=80+10*7, а не в выражение t=(80+10)*7, как это получается при наличии скобок, и в результате вычислений получится число 150, а не 630.

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

        1. Определение констант в программе

Наглядность и переносимость программы можно улучшить, заменяя ссылки кконкретным значениям, например 512, их мнемоническими обозначениями. Константой называется имя, которое связывается Си-компилятором с неизменяемым в программезначением. Для создания константы используется директива #define или первая форма записи Например, следующая директива определяет константу по имени LINE_SIZE, с которой связывается значение 128:

#define LINE_SIZE 128

Встречая в дальнейшем в программе имя LINE_SIZE, препроцессор языка Си заменяет его значением константы. Например, рассмотрим объявления следующих символьных строк:

char line[128] ;

char text[128] ;

char current_line[LINE_SIZE] ;

char user_input[LINE_SIZE];

Первые два объявления создают символьные строки, каждая из которых рассчитана на 128 символов. Следующие два объявления создают символьные строки, используя константу с именем LINE_SIZE. При чтении программы другим программистом может возникнуть вопрос, связанный с употреблением числа 128 в объявлении переменных. В то же время объявления, использующие имя константы LINE_SIZE вместо самого значения константы, ясно дают понять, что строки объявлены в терминах предопределенного имени LINEJ5IZE. В программу могут также включаться циклы, аналогичные следующим:

for (i = 0; i < 128; i++)

// операторы

for (i = 0; i < LINE_SIZE; i++)

// операторы

Второй цикл for является не только более наглядным, но и делает программу более удобной для внесения изменений. Предположим, что для определения длины строки в программе используется значение 128. Если позднее возникает необходимость увеличить размер строки до 256 символов, нужно изменить в программе каждое появление значения 128 - процесс, требующий времени. С другой стороны, если используется константа, такая как LINE_SIZE, то достаточно лишь изменить директиву #define:

#define LINE_SIZE 256

            1. Подстановка макрокоманд и констант

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

#define LINE 128

#define TITLE "1001 совет по С & C++"

#define SECTION "Макрокоманды "

void main (void)

{

char book [LINE] ;

char library_name [LINE] ;

printf("Название этой книги %s\n",TITLE);

printf (SECTION) ;

}

Компиляция Си-программы начинается с работы препроцессора. Назначение препроцессора - включение заданных заголовочных файлов и подстановка макрокоманд (макрорасширение) и констант. Прежде чем Си-компилятор действительно начнет компилировать программу с помощью препроцессора, каждое имя константы заменяется значением этой константы следующим образом:

void main (void)

{

char book [128] ;

char library_name [128] ;

printf("Название этой книги %s\n", "1001 совет по С S C++") ;

printf("Макрокоманды ");

}

        1. Выбор имен для констант и макрокоманд

Константой является имя, которое связывается Си-компилятором с неизменяемым в программе значением. Для используемых в программе констант и макрокоманд следует выбирать содержательные имена. Кроме этого, чтобы помочь программисту, читающему исходный код, отличать имена констант от имен переменных, для задания имен констант и макрокоманд рекомендуется использовать прописные буквы. Следующие директивы #define содержат различные определения макрокоманд (макроопределения):

#define TRUE 1

#define FALSE 0

#define PI 3.1415

#define PROGRAMMER "Kris Jamsa"

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