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