Новосибирский Государственный Университет
Опубликован: 26.08.2005 | Доступ: свободный | Студентов: 19045 / 3448 | Оценка: 4.07 / 3.55 | Длительность: 13:11:00
ISBN: 978-5-9556-0057-4
Лекция 11:

Препроцессор языка Си

< Лекция 10 || Лекция 11: 12345 || Лекция 12 >
Аннотация: Общие сведения. Символические константы: #define. Использование аргументов с #define. Макроопределение или функция? Включение файла #include. Условная компиляция.

Общие сведения

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

  1. Все системно-зависимые обозначения перекодируются в стандартные коды.
  2. Каждая пара из символов ' \ ' и "конец строки" вместе с пробелами между ними убираются, и тем самым следующая строка исходного текста присоединяется к строке, в которой находилась эта пара символов.
  3. В тексте распознаются директивы и лексемы препроцессора, а каждый комментарий заменяется одним символом пустого промежутка.
  4. Выполняются директивы препроцессора и производятся макроподстановки.
  5. Эскейп-последовательности в символьных константах и символьных строках заменяются на их эквиваленты.
  6. Смежные символьные строки конкатенируются, то есть соединяются в одну строку.
  7. Каждая препроцессорная лексема преобразуется в текст на языке Си.

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

Стадия обработки директив препроцессора. При ее выполнении возможны следующие действия:

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

Символические константы: #define

Если в качестве первого символа в строке программы используется символ #, то эта строка является командной строкой препроцессора (макропроцессора). Командная строка препроцессора заканчивается символом перевода на новую строку. Если непосредственно перед концом строки поставить символ обратной косой черты " \ ", то командная строка будет продолжена на следующую строку программы.

Директива #define, подобно всем директивам препроцессора, начинается c символа # в самой левой позиции. Она может появиться в любом месте исходного файла, а даваемое определение имеет силу от места появления до конца файла. Мы активно используем эту директиву для определения символических констант в наших примерах программ, однако она имеет более широкое применение, что мы покажем дальше.

Замена идентификаторов

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

Пример:

#define ABC 100

Заменяет каждое вхождение идентификатора ABC в тексте программы на 100:

#undef идентификатор

Пример:

#undef ABC

Отменяет предыдущее определение для идентификатора ABC.

Пример:

/* Простые примеры директивы препроцессора */
#define TWO 2 /* можно использовать комментарии*/
#define MSG "Текст 1.\
Продолжение текста 1"
/* обратная косая черта продолжает определение на следующую строку */
#define FOUR TWO*TWO
#define PX printf("X равен %d.\n", x)
#define FMT "X равен %d.\n"
int main( )
{
	int x = TWO;
	PX;
	x = FOUR;
	printf(FMT,x);
	printf("%s\n",MSG);
	printf("TWO: MSG\n");
	return TWO;
}

В результате выполнения нашего примера будем иметь:

X равен 2
X равен 4
Текст 1. Продолжение текста 1
TWO: MSG

Разберем, что произошло. Оператор

int x = TWO;

превращается в

int x = 2;

Затем оператор

PX;

превращается в

printf("X равно %d.\n",x);

поскольку сделана полная замена. Теперь мы видим, что макроопределение может представлять любую строку, даже целое выражение на языке Си. Заметим, что это константная строка. PX напечатает только переменную, названную x.

< Лекция 10 || Лекция 11: 12345 || Лекция 12 >
Иван Руднев
Иван Руднев
Фраза "Структурная переменная описывается с помощью переменной структурного типа" на мой Взгляд является тафтология. Из нее сложно понять суть утверждения. Хотелось бы полке понятного описания.
Руслан Поддубный
Руслан Поддубный

"

printf("Добро пожаловать!\n");  - на консоль выводится непонятный набор знаков вместо русского текста.