СИМВОЛИЧЕСКИЕ КОНСТАНТЫ: #define
Директива #define, подобно всем директивам препроцессора, начинается с символа #в самой левой позиции. Она может появиться в любом месте исходного файла, а даваемое ею определение имеет силу от места появления до конца файла. Мы активно используем эту директиву для определения символических констант в наших программах, однако она имеет более широкое применение; что мы и покажем дальше. Вот пример, иллюстрирующий некоторые возможности и свойства директивы #define:
/* простые примеры директивы препроцессора */
#define TWO 2 /* по желанию можно использовать комментарии */
#define MSG "Старый серый кот поет веселую песню."
/* обратная косая черта продолжает определение на следующую строку */
#define FOUR TWO *TWO
#define PX printf("X равен %d.\n", x)
#define FMT "X равен %d.\n"
main( )
{
int x = TWO;
PX;
x = FOUR;
printf(FMT, x);
printf( "%s\n", MSG);
printf("FTWO: MSG\n");
}
Каждая строка состоит из трех частей. Первой стоит директива #define. Далее идет выбранная нами аббревиатура, известная у программистов как "макроопределение". Макроопределение не должно содержать внутри себя пробелы. И наконец, идет строка (называемая "строкой замещения" ), которую представляет макроопределение. Когда препроцессор находит в программе одно из ваших макроопределений, он почти всегда заменяет его строкой замещения. (Есть одно исключение, которое мы вам сейчас покажем.) Этот процесс прохождения от макроопределения до заключительной строки замещения называется "макрорасширением". Заметим, что при стандартной форме записи на языке Си можно вставлять комментарии; они будут игнорироваться препроцессором. Кроме того, большинство систем разрешает использовать обратную косую черту ( '\') для расширения определения более чем на одну строку.
"Запустим" наш пример, и посмотрим за его выполнением.
Х равен 2.
Х равен 4.
Старый серый кот поет веселую песню. TWO: MSG
Вот что произошло. Оператор int x = TWO;превращается в int x = 2;.

РИС. 11.1. Части макроопределения.
т. е. слово TWOзаменилось цифрой 2. Затем оператор РХ;превращается в printf("X равно %d. \n", х);поскольку сделана полная замена. Это новшество, так как до сих пор мы использовали макроопределения только для представления констант. Теперь же мы видим, что макроопределение может представлять любую строку, даже целое выражение на языке Си. Заметим, однако, что это константная строка; РХнапечатает только переменную, названную x.
Следующая строка также представляет что-то новое. Вы можете подумать, что FOURзаменяется на 4, но на самом деле выполняется следующее:
х = FOUR;
превращается в х = TWO *TWO;превращается в х = 2*2;и на этом все заканчивается. Фактическое умножение имеет место не во время работы препроцессора и не при компиляции, а всегда без исключения при работе программы. Препроцессор не выполняет вычислений; он только очень точно делает предложенные подстановки.
Заметим, что макроопределение может включать другие определения. (Некоторые компиляторы не поддерживают это свойство "вложения".)
В следующей строке printf(FMT, х);превращается в printf(" Х равно %d.\n", х)когда FMTзаменяется соответствующей строкой. Этот подход может оказаться очень удобным, если у вас есть длинная строка, которую вы используете несколько раз.
В следующей строке программы MSGзаменяется соответствующей строкой. Кавычки делают замещающую строку константой символьной строки; поскольку программа получает ее содержимое, эта строка будет запоминаться в массиве, заканчивающемся нуль-символом. Так, #define HAL 'Z'определяет символьную константу, а #define НАР "Z"определяет символьную строку: Z\0.
Обычно препроцессор, встречая одно из ваших макроопределений в программе, очень точно заменяет их эквивалентной строкой замещения. Если эта строка также содержит макроопределения, они тоже замешаются. Единственным исключением при замене является макроопределение, находящееся внутри двойных кавычек. Поэтому printf("TWO: MSG");печатает буквально TWO: MSGвместо печати следующей строки:
Читать дальше