Почему заменители аргументов не заменяются при повторном сканировании?
Рассмотрим следующие макроопределения и вызовы:
#define x x[0]
#define y(arg) arg
y(x)
Этот вызов расширяется до x[0]
(тестируется на Visual С++ 2010, g++ 4.1, mcpp 2.7.2 и Wave).
Почему? В частности, почему он не расширяется до x[0][0]
?
Во время замены макроса
Параметр в списке замены... заменяется соответствующим аргументом после того, как все макросы, содержащиеся в нем, были расширены. Перед заменой каждый токер предварительной обработки аргументов полностью заменяется макросом (С++ 03 §16.3.1/1).
Оценивая вызов макроса, мы делаем следующие шаги:
- Функциональный макрос
y
вызывается с помощью x
в качестве аргумента для параметра arg
-
x
в аргументе заменяется макросом, становясь x[0]
-
arg
в списке замещения заменяется заменяемым макросом значением аргумента, x[0]
Список заметок после подстановки всех параметров x[0]
.
После того, как все параметры в списке замещения были заменены, результирующая последовательность токенов препроцессора будет rescanned... для замены более имени макроса (С++ 03 §16.3.4/1).
Если имя заменяемого макроса найдено во время сканирования списка замены... оно не заменяется. Кроме того, если какие-либо вложенные замены встречаются с именем заменяемого макроса, он не заменяется (С++ 03 §16.3.4/2).
Заменен список замены x[0]
(обратите внимание, что имя заменяемого макроса y
):
-
x
идентифицируется как объект-подобный вызов макроса
-
x
заменяется на x[0]
Замена останавливается на этом этапе из-за правила в §16.3.4/2, предотвращающего рекурсию. Список замены после повторного сканирования - x[0][0]
.
Я явно неправильно истолковал что-то, потому что все препроцессоры, которые я тестировал, говорят, что я ошибаюсь. Кроме того, этот пример является куском большего примера в С++ 0x FCD (в §16.3.5/5), и он также говорит, что ожидаемая замена x[0]
.
Почему x
не заменяется во время повторного сканирования?
C99 и С++ 0x фактически имеют ту же формулировку, что и С++ 03 в цитируемых разделах.
Ответы
Ответ 1
Я считаю, что вы процитировали ключевой параграф, вы просто остановились слишком рано. 16.3.4/2 (основное внимание):
Если имя заменяемого макроса найдено во время этого сканирования список замены (не включая остальные исходные файлы токены предварительной обработки), это не заменены. Кроме того, если какой-либо вложенный встреча замещений имя заменяемого макроса, он не заменяется. Эти неприменимые маркеры предварительной обработки макросов не являются дольше доступны для дальнейшего замена, даже если они позже (re) в контекстах, в которых маркер предварительной обработки макросов в противном случае были заменены.
Итак, когда x
заменяется на x[0]
во время замены параметра y
, он полностью заменяется макросом, что означает, что он повторно сканируется в этой точке, а x
попадает в правило рекурсии. Это означает, что x
in x[0]
больше не подходит для дальнейшей замены, в том числе при повторном сканировании частично расширенного результата y(x)
.