Типичное применение препроцессорных директив
В этом коротком разделе мы покажем только некоторые из наиболее распространенных случаев, когда препроцессорные директивы могут оказаться полезны.
Предотвращение включения файлов
Иногда при использовании заголовков может происходить дублирование кода из-за повторного включения некоторого файла. (Допустим, у вас имеется исходный файл myprog.c, который подключает директивой # include два заголовка headerl.h и header2.h. Если, в свою очередь, оба этих файла подключают некоторый headerO.h, то последний будет дважды включен в исходный файл myprog.c. Это ни к чему, хотя обычно и не приводит к ошибке.)
Чтобы предотвратить повторное включение кода заголовочного файла, можно организовать контроль следующим образом (как говорят, “поставить часового”):
/*
** header0.h: Заголовочный файл, который может оказаться
** многократно включенным...
*/
#ifndef _HEADERO_H
#define _HEADERO_H
/* /
** Здесь идут макросы, определения типов
** и т.д. вашего заголовочного файла...
*/
*endif
Переключение разделов кода
Директивы условной компиляции могут использоваться для простого переключения между двумя различными вариантами кода — старым и экспериментальным алгоритмом, например. Это можно сделать так:
/*
** Измените определение на 0, чтобы вернуться к старому варианту.
*/
*define NEW_VER I
#if NEW_VER /*
** Экспериментальный код.
*/
#else /*
** Старый код.
*/
*endif
Или, если не вводить дополнительный идентификатор:
/*
** Измените на 1, когда новый код будет отлажен.
*/
*if 0 /*
** Экспериментальный код.
*/
#else /*
* * Старый код.
*/
*endif
Отладочные диагностические сообщения
При отладке программ можно с большой пользой применять макросы, генерирующие операторы вывода различных сообщений с указанием файла и номера строки, например:
#define INFO(msg)
printf(#msg "\n")
#define DIAG(msg)
printf("File " _FILE_ " Line %d: " \ #msg "\n", _LINE_)
void SomeFunc(void)
{
INFO(Entering SomeFunc.);
/* Выводит информационное сообщение. */
if (someError)
DIAG(Error encountered!);
/* Выводит сообщение об ошибке. */
INFO(Exiting SomeFunc...) ;
}
Макрос assert()
В заголовочном файле assert.h определен макрос assert (), выполняющий примерно то же самое, что и показанный выше пример. Его “прототип” можно записать как
void assert(int test);
Макрос расширяется в оператор if, проверяющий условие test. Если его значение равно 0, печатается сообщение Assertion failed: с указанием имени файла и номера строки. Вот пример:
#include <assert.h>
…
assert(!someError) ;
Если перед включением 41айла assert.h определить символ ndebug, операторы assert () будут “закомментированы”.