Пересмотр списка макросов для замены - PullRequest
0 голосов
/ 15 января 2019

Я читаю Стандарт N1570 о замене макросов и неправильно понимаю некоторые формулировки из 6.10.3.4.

1 После того, как все параметры в списке замены были заменены и обработаны # и ##, вся предварительная обработка меток токены удалены Результирующая последовательность токена предварительной обработки затем повторно сканируется вместе со всеми последующими токенами предварительной обработки исходный файл, для дополнительных имен макросов, чтобы заменить

Итак, после того, как все # и ## разрешены, мы повторно сканируем список замены. Но в разделе 2 указано:

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

Это выглядит противоречиво для меня. Итак, какая замена возможна в этом повторном сканировании? Я попробовал следующий пример:

#define FOOBAR(a, b) printf(#a #b)

#define INVOKE(a, b) a##b(a, b)

int main() {
    INVOKE(FOO, BAR); //expands to printf("FOO" "BAR")
}

Таким образом, INVOKE(FOO, BAR) расширяется до FOOBAR(FOO, BAR) после замены ##. Затем список замены FOOBAR(FOO, BAR) повторно сканируется. Но в разделе 2. указано, что имя заменяемого макроса (FOOBAR) найдено (да, определено выше), но не заменено (но фактически заменено, как это видно в демонстрационном примере).

Не могли бы вы уточнить эту формулировку? Что я пропустил?

LIVE DEMO

Ответы [ 2 ]

0 голосов
/ 15 января 2019

Рассмотрим следующий простой пример:

#include<stdio.h>

const int FOO = 42;

#define FOO (42 + FOO) 

int main()
{
   printf("%d", FOO);
}

Здесь результат будет 84.

printf будет расширен до:

printf("%d", 42 + 42);

Этоозначает, что при расширении макроса FOO расширение остановится, когда будет найден второй FOO.Это не будет дальше расширяться.В противном случае вы получите бесконечную рекурсию, в результате чего: 42 + (42 + (42 + (42 + ....)

Live демо здесь .

0 голосов
/ 15 января 2019

Заменяемый (оригинальный) макрос - это не FOOBAR, а INVOKE. Когда вы расширяете INVOKE и обнаруживаете FOOBAR, вы расширяете FOOBAR как обычно. Однако, если INVOKE было найдено при расширении INVOKE, оно больше не будет расширяться.

Давайте возьмем следующий код:

#define FOOBAR(a, b) printf(#a #b)

#define INVOKE(a, b) e1 a##b(a, b)

int main() {
    INVOKE(INV, OKE);
}

Я добавил e1 к расширению INVOKE, чтобы иметь возможность визуализировать, сколько происходит расширений. Результат предварительной обработки main:

e1 INVOKE(INV, OKE);

Это доказывает, что INVOKE был расширен один раз, а затем, после повторного сканирования, не расширен снова.

[Живой пример]

...