Компилятор обычно выделяет регистровую память переменным в том порядке, в котором записаны объявления переменных в программе. Если программа содержит больше объявлений переменных класса памяти register, чем имеется регистров в данной операционной среде, то регистровую память получат только те переменные, объявления которых записаны раньше. Следовательно, если более интенсивно будут использоваться те переменные, которые объявлены позже, выигрыш в эффективности от использования регистров окажется незначительным.
В примере показано, каким образом предоставить приоритет регистровой памяти наиболее важным переменным. Именованные константы REG1 и REG2 определяются как ключевые слова register. Они предназначены для объявления двух наиболее важных локальных переменных функции. Например, в следующем фрагменте программы такими переменными являются b и c.
func(REG3 int а)
{
REG1 int b;
REG2 int c;
REG4 int d;
}
Если определена константа М_86, препроцессор удаляет идентификаторы REG3 и REG4 из файла путем замены их на пустой текст. Регистровую память в этом случае получат только переменные b и с. Если определен идентификатор М_68000, то все четыре переменные объявляются с классом памяти register.
Если не определена ни одна из констант — ни М_86, ни М_68000, — то регистровую память получат переменные а, b и с.
Директивы #ifdef и #ifndef
Синтаксис:
#ifdef <
#ifndef <
Аналогично директиве #if, за директивами #ifdef и #ifndef может следовать набор директив #elif и директива #else. Набор должен быть завершен директивой #endif.
Использование директив #ifdef и #ifndef эквивалентно применению директивы #if, использующей выражение с операцией defined(<
Когда препроцессор обрабатывает директиву #ifdef, он проверяет, определен ли в данный момент <
Директива #ifndef противоположна по действию директиве #ifdef. Если <
Управление нумерацией строк
Синтаксис:
#line <
Директива #line сообщает компилятору языка Си об изменении имени исходного файла и порядка нумерации строк. Это изменение отражается только на диагностических сообщениях компилятора: исходный файл будет теперь именоваться как <
Директива #line обычно используется автоматическими генераторами программ для того, чтобы диагностические сообщения относились не к исходному файлу, а к сгенерированной программе.
<
Текущий номер строки и имя исходного файла доступны в программе через псевдопеременные с именами __LINE__ и __FILE__. Эти псевдопеременные могут быть использованы для выдачи во время выполнения сообщений о точном местоположении ошибки.
Значением псевдопеременной __FILE__ является строка, представляющая имя файла, заключенное в двойные кавычки. Поэтому для печати имени исходного файла не требуется заключать сам идентификатор __FILE__ в двойные кавычки.
Примеры.
#line 151 "copy.с"
/* пример 2 */
#define ASSERT(cond) if (!cond)\
{printf ("ошибка в строке %d файла %s\n", \
__LINE__, __FILE__);} else;
В первом примере устанавливается имя исходного файла сору.с и текущий номер строки 151.
Во втором примере в макроопределении ASSERT используются псевдопеременные __LINE__ и __FILE__ для печати сообщения об ошибке, содержащего координаты исходного файла, если некоторое условие, заданное макроаргументом cond, ложно.
Директива обработки ошибок
В СП ТС реализована директива #error. Ее формат:
#error <
Обычно эту директиву записывают среди директив условной компиляции для обнаружения некоторой недопустимой ситуации. По директиве #error препроцессор прерывает компиляцию и выдает следующее сообщение:
Fatal: <