Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Название:Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:0101
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 краткое содержание
Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Первые шаги в трансляции программы
До передачи управления препроцессору компилятор должен провести программу через ряд этапов трансляции. Компилятор начинает свою работу с того, что устанавливает соответствие символов исходного кода с исходным набором символов. При этом обрабатываются многобайтные символы и триграфы — расширения символов, которые обеспечивают интернациональное применение языка С. (Обзор этих расширений приведен в справочном разделе VII приложения Б.)
Во вторую очередь компилятор обнаруживает все вхождения обратной косой черты с последующим символом новой строки и удаляет их. В результате две физические строки,такие как
printf("Это было вели\ колепно!\n");
преобразуются в одну логическую строку: printf("Это было великолепно!\n");
Обратите внимание, что в этом контексте “символ новой строки” означает символ, сгенерированный нажатием клавиши для перехода на следующую строку в файле исходного кода, а не символическое представление \n.
Это необходимо для подготовки к предварительной обработке, поскольку препроцессор требует, чтобы выражения имели длину, равную одной логической строке, но одна логическая строка может распрос траняться на несколько физических строк.
Далее компилятор разбивает текст на последовательность иреироцессорных лексем, а также на последовательности пробельных символов и комментариев. (В базовой терминологии лексемы представляют собой группы, отделяемые друг от друга пробелами, табуляциями или разрывами строк; позже мы рассмотрим лексемы более подробно.) Сейчас интересно отметить, что каждый комментарий заменяется одним символом пробела. Таким образом, код следующего вида:
int/* это не похоже на пробел */fox; превращается в int fox;
Препроцессор и библиотека С 663
Кроме того, в рамках реализации компилятора может быть принято решение заменять каждую последовательность пробельных символов (кроме символа новой строки) одиночным пробелом. Наконец, программа готова для этапа предварительной обработки, и препроцессор начинает поиск своих потенциальных директив, обозначаемых символом # в начале строки.
Символические константы: #def ine
Подобно всем директивам препроцессора, директива #define начинается с символа # в начале строки. Стандарт ANSI и последующие стандарты разрешают предварение символа # пробелами или табуляциями, а также наличие пробела между # и остальной частью директивы. Однако в прежних версиях С обычно требовалось, чтобы директива начиналась в крайней левой позиции в строке, а пробелы между символом # и остальной частью директивы не допускались. Директива может находиться в любом месте файла исходного кода, и ее определение распространяется от этого места до конца файла. В наших программах мы интенсивно использовали директивы для определения символических, или именованных, констант. Однако, как вскоре будет показано, область применения директив этим не ограничивается. В листинге 16.1 продемонстрированы некоторые возможности и свойства директивы #def ine.
Листинг 16.1. Программа prергос.с
Директива препроцессора простирается до тех пор, пока не встретится первый символ новой строки после знака #. Другими словами, длина директивы ограничена одной строкой. Однако, как уже упоминалось ранее, комбинации обратной косой черты и символа новой строки удаляются до начала работы препроцессора, поэтому директиву можно распространить на несколько физических строк. Тем не менее, эти строки образуют одну логическую строку.
Каждая строка #define (т.е. логическая строка) состоит из трех частей. Первая часть — это сама директива #define. Вторая часть — выбранное программистом сокращение, называемое макросом. Некоторые макросы, как в приведенном выше примере, представляют значения. Они называются объектными макросами. (В языке С еще существуют функциональные макросы, о которых речь пойдет позже.)
664 Глава 16
Имя макроса не должно содержать пробелов. На макросы распространяются правила именования переменных: разрешены только буквы, цифры и символ подчеркивания (_), а первым символом не должна быть цифра. Третья часть (остаток строки) называется списком замены или телом (рис. 16.1). Когда препроцессор обнаруживает в программе имя одного из макросов, он почти всегда заменяет его телом. (Как вскоре будет показано, из этого правила существует одно исключение.) Этот процесс перехода от макроса к подставляемому итоговому значению называется расширением. Обратите внимание, что в строке #define могут быть указаны стандартные комментарии; ранее уже говорилось о том, до начала работы препроцессора каждый комментарий заменяется пробелом.
Рис. 16.1. Части определения объектного макроса
Давайте запустим программу и посмотрим, как она работает:
X = 2.
X = 4.
Логика - последнее убежище лишенных воображения. - Оскар Уайльд TWO: 0W
Здесь вот что происходит. Оператор
int х = TWO;
преобразуется следующим образом:
int х = 2;
поскольку вместо TWO было подставлено 2. Затем оператор
РХ;
приобретает следующий вид:
printf("Х= %d.\n", х);
Подстановка осуществилась для всего оператора целиком. Это новый прием, т.к. до сих пор мы использовали макросы только для представления констант. Здесь вы видите, что макрос может представлять любую строку, даже целое выражение С. Однако отметим, что это константная строка; макрос РХ будет выводить только значение переменной по имени х.
В следующей строке также демонстрируется новый прием. Может показаться, что FOUR будете заменено 4, но на самом деле процесс был другим. Строка
х = FOUR;
преобразуется в строку
х = TWO*TWO;
которая затем становится следующей:
X = 2*2;
Препроцессор и библиотека С 665
На этом процесс расширения макроса завершен. Действительное умножение происходит не во время работы препроцессора, а на этапе компиляции, поскольку компилятор С на этой стадии вычисляет все константные выражения (т.е. выражения, которые содержат только константы). Препроцессор не выполняет вычислений, а просто совершенно буквально производит указанные с помощью директив подстановки.
Обратите внимание, что определение макроса может включать другие макросы. (Некоторые компиляторы такую вложенность макросов не поддерживают.) Следующая строка
printf (FMT, х); приводится к виду:
printf("X = %d.\n",х);
потому что FMT заменяется соответствующей строкой. Такой подход может оказаться удобным при наличии длинной управляющей строки, которую приходится применять несколько раз. Вместо этого можно было поступить следующим образом:
Читать дальшеИнтервал:
Закладка: