Почему замены аргументов не заменяются во время повторного сканирования? - PullRequest
12 голосов
/ 01 июня 2010

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

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

1 Ответ

17 голосов
/ 01 июня 2010

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

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

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

...