Препроцессор изменяет номер текущей строки и имя компилируемого файла. Имя файла может быть опущено.
Одна из целей использования условной компиляции - сделать программу более мобильной. Изменяя несколько ключевых определений в начале файла, мы можем устанавливать различные значения и включать различные файлы для разных систем.
#define N 3/*определение константы */
void main( )
{
#line 55 "file.c"
double x[3*N];
}
Реакция на ошибки
#error последовательность лексем
Обработка директивы приводит к выдаче диагностического сообщения в виде, определенном последовательностью лексем. Применение этой директивы совместно с условными препроцессорными командами.
Пример:
В дальнейшем можно проверить ее значение и выдать сообщение, если у NAME окажется другое значение:
#if (NAME !=15)
#error NAME должно быть равно 15!
Сообщение будет выглядеть так:
error <имя_файла><номер_строки >;
error directive: NAME должно быть равно 15!
Пустая директива
Использование этой директивы не вызывает никаких действий.
Прагмы
Эта директива определяет действия, зависящие от конкретной реализации компилятора. Например в некоторые компиляторы входит вариант этой директивы для извещения компилятора о наличии в тексте программы команд на языке Ассемблер. Возможности команды #pragma могут быть разнообазными. Стандарта для них не существует. Если конкретный препроцессор встречает прагму, которая ему неизвестна, он ее просто игнорирует как пустую директиву. В некоторых реализациях включена прагма.
#pragma pack(n), где n= 1, 2, 4. Прагма pack позволяет влиять на упаковку смежных элементов в структурах и объединениях (см. лекцию 14).
Соглашение может быть таким:
pack(1) - выравнивание элементов по границам байтов;
pack(2) - выравнивание элементов по границам слов;
pack(4) - выравнивание элементов по границам двойных слов;
В некоторые компиляторы включены прагмы, позволяющие изменять способ передачи параметров функциям, порядок помещения параметров в стек и т.д.
Встроенные макроимена
Существуют встроенные (заранее определенные) макроимена, доступные препроцессору во время обработки. Они позволяют получить следующую информацию:
__DATE__ - строка символов в формате: "месяц число год", определяющая дату начала обработки исходного файла. Например, после препроцессорной обработки текста программы, выполненной 29 января 2005 года, оператор
станет таким
printf("%s", "January 29 2005");
__LINE__ - десятичная константа - номер текущей обрабатываемой строки файла с программой на Си. Принято, что номер первой строки исходного файла равен 1 ;
__FILE__ - строка символов - имя компилируемого файла. Имя изменяется всякий раз, когда препроцессор встречает директиву#include с указанием имени другого файла. Когда включения файла по команде #include завершаются, востанавливается предыдущее значение макроимени __FILE__ ;
__TIME__ - строка символов вида "часы:минуты:секунды", определяющая время начала обработки препроцессором исходного файла;
__STDC__ - константа, равная 1, если компилятор работает в соответствии с ANSI-стандартом. В противном случае значениемикроимени __STDC__ не определено. Стандарт языка Си предполагает, что наличие имени __STDC__ определяется реализацией, так как макрос __STDC__ относится к нововведениям стандарта. В конкретных реализациях набор предопределенных имен гораздо шире. Для получения более полных сведений о предопределенных препроцессорных именах следует обращаться к документации поконкретному компилятору.