При развертывании макроса препроцессор раскрывает аргументы макроса , только если эти аргументы не подвергаются операторам stringizing (#
) или вставки токенов (##
) . Итак, если у вас есть это:
#define stringify(x) #x
stringify(__LINE__)
Затем препроцессор не раскрывает __LINE__
, потому что это аргумент оператора stringizing. Однако, когда вы делаете это:
#define stringify1(x) #x
#define stringify(x) stringify1(x)
stringify(__LINE__)
Затем при расширении stringify
препроцессор расширяет __LINE__
до текущего номера строки, поскольку x
не используется ни с операторами строкового преобразования, ни с вставкой токена в определении stringify
. Затем он расширяется stringify1
, и мы получаем то, что хотели.
Соответствующий язык из стандарта C99 взят из §6.10.3.1 / 1:
После того как аргументы для вызова функционально-подобного макроса были идентифицированы, происходит подстановка аргументов. Параметр в списке замены, если перед ним не стоит токен предварительной обработки #
или ##
или за ним не идет токен предварительной обработки ##
(см. Ниже), заменяется соответствующим аргументом после раскрытия всех содержащихся в нем макросов. Перед заменой токены предварительной обработки каждого аргумента полностью заменяются макросами, как если бы они образовывали остальную часть файла предварительной обработки; другие токены предварительной обработки недоступны.
Пункты § 6.10.3.2 и 6.10.3.3 продолжают определять поведение операторов #
и ##
соответственно.