Рассмотрим следующие макроопределения и вызовы:
#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 в цитируемых разделах.