Почему при повторном сканировании замены аргументов не заменяются?

Рассмотрим следующие определения макросов и их вызовы:

#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 в цитируемых разделах.


person James McNellis    schedule 01.06.2010    source источник


Ответы (1)


Я считаю, что вы процитировали ключевой абзац, вы просто остановились слишком рано. 16.3.4 / 2 (выделено мной):

Если имя заменяемого макроса обнаружено во время этого сканирования списка замены (не включая оставшиеся токены предварительной обработки исходного файла), он не заменяется. Кроме того, если какие-либо вложенные замены встречаются с именем заменяемого макроса, оно не заменяется. Эти незамещенные токены предварительной обработки имени макроса больше не доступны для дальнейшей замены, даже если они позже (повторно) проверяются в контекстах, в которых в противном случае токен предварительной обработки имени макроса был бы заменен.

Таким образом, когда x заменяется на x[0] во время подстановки параметра y, он полностью заменяется макросом, что означает, что он повторно сканируется в этой точке, и x перехватывается правилом рекурсии. Это означает, что x в x[0] больше не подлежит дальнейшей замене, в том числе во время повторного сканирования частично расширенного результата y(x).

person Steve Jessop    schedule 01.06.2010
comment
Ага! Я забыл, что список замены x будет повторно сканироваться перед заменой; теперь все имеет смысл. Спасибо, Стив. - person James McNellis; 01.06.2010