#if SYS == 1
#include "ibmpc.h"
#elif SYS = 2
#include "vax.h"
#elif SYS == 3
#include "mac.h"
#else
#include "general.h"
#endif
В более новых реализациях предлагается второй способ проверки, определено ли имя. Вместо строки
#ifdef VAX
можно применять следующую форму записи:
#if defined (VAX)
Здесь defined — операция препроцессора, которая возвращает значение 1, если ее аргумент определен с помощью директивы #define, и 0 в противном случае. Преимущество такой новой формы состоит в том, что в нее можно использовать вместе с #elif. Исходя из этого, предыдущий пример можно переписать следующим образом:
#if defined (IBMPC)
#include "ibmpc.h"
#elif defined (VAX)
#include "vax.h"
#elif defined (MAC)
#include "mac.h"
#else
#include "general.h"
#endif
Если приведенные строки применяются, скажем, в системе VAX, идентификатор VAX должен быть определен где-то раньше в этом файле посредством такой строки:
#define VAX
684 Глава 16
Одной из целей использования средств условной компиляции является обеспечение переносимости программы. За счет изменения нескольких ключевых определений в начале файла можно настраивать разные значения и включать определенные файлы для различных систем.
Предопределенные макросы
В стандарте С описано несколько предопределенных макросов, которые перечислены в табл. 16.1.
Таблица 16.1. Предопределенные макросы

Следует отметить, что стандарт С99 предоставляет предопределенный идентификатор func , который расширяется до строкового представления имени содер
жащей его функции. По этой причине данный идентификатор должен иметь область действия в пределах функции, в то время как макросы по существу располагают областью действия на уровне файла. Таким образом, func является предопределен
ным идентификатором языка С, а не предопределенным макросом.
В листинге 16.12 демонстрируется ряд предопределенных идентификаторов в действии. Обратите внимание, что некоторые из них являются нововведениями стандарта С99, поэтому компиляторы, разработанные до появления этого стандарта, могут их не принимать. Для компилятора GCC может понадобиться указать флаг -std=c99 или -std=c11.
Листинг 16.12. Программа predef .с

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

Вот как выглядит вывод, полученный в результате пробного запуска программы:
Директивы #line И terror
Директива #line позволяет переустанавливать нумерацию строк и имя файла, выводимые с помощью макросов LINE_____________________________ и_____ FILE . Директиву #line можно ис
пользовать следующим образом:
#line 1000 //переустанавливает текущий номер строки в 1000
#line 10 "cool.с" //переустанавливает номер строки в 10, а имя файла - в cool. с
Директива #error заставляет препроцессор выдать сообщение об ошибке, которое включает любой текст, указанный в директиве. Если это возможно, процесс компиляции должен приостановиться. Директиву можно применять так:
#if STDC_VERSION != 201112L
#error Несоответствие СИ
#endif
После этого попытка компиляции программы могла бы привести к получению следующих результатов:
$ gcc newish.с
newish.с:14:2 : error: #error Несоответствие СИ $ gcc -std=c11 newish.с
$
Процесс компиляции не проходит, когда компилятор использует более старый стандарт, и завершается успешно, когда применяется стандарт СИ.
Директива #pragma
У современных компиляторов существует несколько настроек, которые можно модифицировать с помощью аргументов командной строки или через меню ШЕ-среды. Директива #pragma позволяет помещать инструкции для компилятора в исходный код. Например, во время разработки стандарта С99 на него ссылались как на С9Х, и в одном из компиляторов использовалась следующая директива для включения поддержки этого стандарта:
#pragma с9х on
В общем случае каждый компилятор имеет собственный набор указаний. Они могут применяться, например, для управления объемом памяти, выделяемой под автоматические переменные, для установки уровня строгости при проверке ошибок или
686 глава 16 для включения нестандартных языковых средств. В стандарте С99 предоставляются три стандартных указания технической природы, которые здесь не рассматриваются.
Кроме того, стандарт С99 поддерживает операцию препроцессора _Pragma. Она преобразует строку в обычное указание компилятору.
Читать дальше