Как отложить подстановку макросов в каскадно-строковом каскаде - PullRequest
0 голосов
/ 30 мая 2018

Это дополнительный вопрос к этому (а также ближе к актуальной проблеме).

Если у меня есть следующий случай:

#include <stdio.h>

#define FOO_ONE 12
#define FOO_TWO 34
#define BAR_ONE 56
#define BAR_TWO 78

#define FOO 99

#define STRINGIFY(mac) #mac
#define CONCAT(mac1, mac2) STRINGIFY(mac1) STRINGIFY(mac2)
#define MAKE_MAC(mac) CONCAT(mac##_ONE, mac##_TWO)

#define PRINT(mac) printf(#mac ": " MAKE_MAC(mac) "\n")

void main(int argc, char *argv[])
{
    PRINT(FOO);
    PRINT(BAR);
}

Как можно видеть, строковые, сцепленные макросы затем подставляются внутри оператора printf(), который сам находится внутри макроса.

Поскольку FOO определен (как 99), это происходитчто он расширяется до объединения с _ONE и _TWO, эффективно создавая токены 99_ONE и 99_TWO.

Эта программа выводит:

FOO: 99_ONE99_TWO
BAR: 5678

Как я могуотложить расширение макроса FOO (фактически, полностью исключив его, чтобы получить требуемый результат:

FOO: 1234
BAR: 5678

ПРИМЕЧАНИЕ: предположим, что сигнатура макроса PRINT() не может быть изменена (т. е. не может быть добавленапараметр и т. д.) Однако его реализация может быть изменена. Кроме того, определения FOO, FOO_* и BAR_* также не могут быть изменены.

Ответы [ 3 ]

0 голосов
/ 30 мая 2018
Как я могу отложить расширение макроса FOO ... ПРИМЕЧАНИЕ: предположим, что подпись макроса PRINT () не может быть изменена (т. Е. Не может быть добавлен параметр и т. Д.)

Вы можете 't.

Расширения макроса проходят через ряд шагов:

  • Подстановка аргумента
  • Вставка и строковое преобразование в произвольном порядке
  • Повторное сканирование и дальнейшее сканированиезамена

Подстановка аргумента происходит с вашими аргументами;в случае вызова PRINT(FOO), FOO;и это самый первый шаг.К тому времени, когда вы даже заставите препроцессор распознать, что что-то в вашем списке замены является макросом, вы уже давно заменили аргумент.

Правило для замены аргумента таково, что если какой-либо из ваших параметров упоминается в вашемсписок замены, и эти параметры не являются ни строковыми, ни вставляемыми, тогда соответствующий аргумент полностью оценивается, и эти упоминания параметров заменяются результатом.В этом случае PRINT(FOO) после подстановки аргумента приводит к списку замены:

printf(#mac ": " MAKE_MAC(99) "\n")

Опять же, определение MAKE_MAC не имеет значения;он даже не распознается как макрос до повторного сканирования и дальнейшей замены.

Теперь, без вашего ограничения, вы можете отложить FOO от расширения ..., добавив второй параметр к PRINT и вставив в него (который дисквалифицирует его с a.s., и ко времени повторного сканирования).и замена приходит, это будет вызывать ваш следующий макрос).Но с вашим ограничением, вы DOA.

0 голосов
/ 30 мая 2018

Фактическое расширение FOO до 99 происходит в тот момент, когда PRINT расширяется и перед повторным сканированием его тела.Соответствующая часть стандарта ANSI:

6.10.3.1 Подстановка аргумента

1 После того, как определены аргументы для вызова функционально-подобного макроса, происходит подстановка аргумента.,Параметр в списке замены, за исключением случаев, когда перед ним стоит токен предварительной обработки # или ## или после него идет токен предварительной обработки ## (см. Ниже), заменяется соответствующим аргументом после раскрытия всех содержащихся в нем макросов.Перед заменой токены предварительной обработки каждого аргумента полностью заменяются макросами, как если бы они формировали остальную часть файла предварительной обработки;другие токены предварительной обработки недоступны.

В вашем случае вы можете избежать расширения FOO (внутри mac), заменив

#define PRINT(mac) printf(#mac ": " MAKE_MAC(mac) "\n")

на

#define PRINT(mac) printf(#mac ": " CONCAT(mac##_ONE, mac##_TWO) "\n")
0 голосов
/ 30 мая 2018

Если вы можете что-то делать каждый раз, когда используется FOO, вы можете сначала отменить определение порядка макросов для его расширения по своему усмотрению, а затем переопределить его, как в

#undef FOO
PRINT(FOO);
#define FOO 99

, в этом случае он будет расширятьсяна

printf("FOO" ": " "12" "34" "\n");

printf("BAR" ": " "56" "78" "\n");

чтобы напечатать то, что вы хотите.

...