/* arrays.h */
#ifndef SIZE
#define SIZE 100 #endif
(Более старые реализации С могут не разрешать отступ для директивы #define.) Обычно такая конструкция используется для предотвращения множественных определений одного и того же макроса при включении нескольких заголовочных файлов, каждый из которых может содержать определение. В этом случае определение в первом заголовочном файле становится активным, а последующие определения в других заголовочных файлах игнорируются.
Рассмотрим еще один случай применения. Предположим, что в заголовок файла помещена такая строка:
#include "arrays.h"
В результате константа SIZE будет определена как 100. Однако если поместить в заголовок файла следующий код:
#define SIZE 10 #include "arrays.h"
to SIZE устанавливается в 10. Здесь SIZE определяется до обработки файла arrays.h, поэтому строка #define SIZE 100 пропускается. Такой прием можно использовать, например, при тестировании программы с применением массива меньшего размера. Добившись корректной работы программы, можно удалить оператор #def ine SIZE 10 и провести повторную компиляцию. В этом случае никогда не придется думать о модификации самого заголовочного файла arrays.h.
Директива #ifndef часто используется для предотвращения многократного включения файла. По этой причине заголовочные файлы обычно содержат следующие строки:
/* things.h */
#ifndef THINGS_H_
#define THINGS_H_
/* остальная часть включаемого файла */
#endif
Предположим, что этот файл каким-то образом был включен несколько раз. Когда препроцессор встречает первое включение данного файла, идентификатор THINGS_H_ не определен, поэтому он определяется и обрабатывается остальная часть файла. При появлении следующего включения того же самого файла идентификатор THINGS_H_ уже определен, так что остальная часть файла пропускается.
Из-за чего файл может быть включен несколько раз? Наиболее распространенная причина состоит в том, что многие включаемые файлы содержат директивы включения других файлов, поэтому можно явно включить файл, в котором этот указанный файл уже включен. Почему это является проблемой? Некоторые элементы, помещаемые в заголовочные файлы, такие как объявления типов структур, могут встречать-
682 Глава 16 ся в файле только один раз. Во избежание многократного включения в стандартных заголовочных файлах применяется директива #ifndef. Одна из задач заключается в том, чтобы удостовериться, что проверяемый идентификатор не определен в другом месте. Поставщики библиотек обычно решают ее путем использования имени файла в качестве идентификатора, записывая имя в верхнем регистре, заменяя точки символами подчеркивания и добавляя символ подчеркивания (или, возможно, два) в качестве префикса и суффикса. Если вы заглянете, скажем, в файл stdio.h, то можете обнаружить в нем примерно такой код:
#ifndef _STDIO_H #define _STDIO_H // содержимое файла #endif
Вы можете поступать аналогично. Тем не менее, следует избегать применения символа подчеркивания в качестве префикса, т.к. в стандарте указано, что использование подобного года является зарезервированным. Вряд ли вы захотите случайно определить макрос, который конфликтует с чем-либо в стандартных заголовочных файлах. В листинге 16.10 директива #ifndef используется для защиты от многократного включения заголовочного файла из листинга 16.6.
Листинг 16.10. Заголовочный файл names_st.h

Можете протестировать этот заголовочный файл с помощью программы, приведенной в листинге 16.11. Программа должна работать корректно с заголовочным файлом, показанным в листинге 16.10, и не должна успешно компилироваться, если удалить из листинга 16.10 защиту посредством #ifndef.
Листинг 16.11. Программа doubinc1.c

Препроцессор и библиотека С 683

Директивы #if И #elif
Директива #if во многом похожа на обычный оператор if языка С. За #if следует константное целочисленное выражение, которое считается истинным, когда оно имеет ненулевое значение. В выражении могут применяться логические операции и операции отношения:
#if SYS == 1 #include "ibm.h"
#endif
Для расширения комбинации #if-#else можно использовать директиву #elif (в некоторых старых реализациях она недоступна). Рассмотрим следующий пример:
Читать дальше