>printf("x/y=%g\n", x/y);
Внутри фактического аргумента каждый знак " заменяется на \", а каждая \ на \\, так что результат подстановки приводит к правильной символьной константе.
Оператор ## позволяет в макрорасширениях конкатенировать аргументы. Если в замещающем тексте параметр соседствует с ##, то он заменяется соответствующим ему аргументом, а оператор ## и окружающие его символы-разделители выбрасываются. Например, в макроопределении paste конкатенируются два аргумента
>#define paste(front, back) front ## back
так что paste(name, 1) сгенерирует имя name1.
Правила вложенных использований оператора ## не определены; другие подробности, относящиеся к ##, можно найти в приложении A.
Упражнение 4.14. Определите swap(t,x,y) в виде макроса, который осуществляет обмен значениями указанного типа t между аргументами x и y. (Примените блочную структуру.)
4.11.3 Условная компиляция
Самим ходом препроцессирования можно управлять с помощью условных инструкций. Они представляют собой средство для выборочного включения того или иного текста программы в зависимости от значения условия, вычисляемого вовремя компиляции.
Вычисляется константное целое выражение, заданное в строке #if. Это выражение не должно содержать ни одного оператора sizeof или приведения к типу и ни одной enum-константы. Если оно имеет ненулевое значение, то будут включены все последующие строки вплоть до #endif, или #elif, или #else. (Инструкция препроцессора #elif похожа на else if.) Выражение defined(имя) в #if есть 1, если имя было определено, и 0 в противном случае.
Например, чтобы застраховаться от повторного включения заголовочного файла hdr.h, его можно оформить следующим образом:
>#if !defined(HDR)
>#define HDR
>/* здесь содержимое hdr.h */
>#endif
При первом включении файла hdr.h будет определено имя HDR, а при последующих включениях препроцессор обнаружит, что имя HDR уже определено, и перескочит сразу на #endif. Этот прием может оказаться полезным, когда нужно избежать многократного включения одного и того же файла. Если им пользоваться систематически, то в результате каждый заголовочный файл будет сам включать заголовочные файлы, от которых он зависит, освободив от этого занятия пользователя.
Вот пример цепочки проверок имени SYSTEM, позволяющей выбрать нужный файл для включения:
>#if SYSTEM == SYSV
> #define HDR "sysv.h"
>#elif SYSTEM == BSD
> #define HDR "bsd.h"
>#elif SYSTEM == MSDOS
> #define HDR "msdos.h"
>#else
> #define HDR "default.h"
>#endif
>#include HDR
Инструкции #ifdef и #ifndef специально предназначены для проверки того, определено или нет заданное в них имя. И следовательно, первый пример, приведенный выше для иллюстрации