Макрос переводит идентификатор предыдущего макроса вместо его замены
Почему inner_LOAD_ATOM(buffer, ATOM_MAX)
конвертировано в scanf("%" "ATOM_MAX" "s", x)
но завернутая версия не так? Я ожидал, что ATOM_MAX(идентификатор) будет заменен на 10, прежде чем он будет "передан" inner_LOAD_ATOM
или же LOAD_LINE
и делает обертку бесполезной. Более подробный ответ, почему обертка необходима, был бы очень признателен.
#include <stdio.h>
#define ATOM_MAX 10
#define inner_LOAD_ATOM(x, y) scanf("%" #y "s", x) /* inner part */
#define LOAD_ATOM(x, y) inner_LOAD_ATOM(x, y) /* wrapper of inner_LOAD_ATOM */
int main(void)
{
char buffer[ATOM_MAX] = {0, };
/* wrapped works fine */
LOAD_ATOM(buffer, ATOM_MAX);
/* [Warning] unknown conversion
type character 'A' in format [-Wformat=] */
inner_LOAD_ATOM(buffer, ATOM_MAX);
printf("%s\n", buffer);
return 0;
}
2 ответа
Важно понимать, что функционально-подобные макросы не работают как Си-функции. Нет (почти) никакого смысла в стеке вызовов макросов или в пересылке аргументов из одного макроса в другой. Вместо этого расширение макроса происходит итеративно - макрос заменяется его расширением, затем расширение повторно сканируется для дальнейшего расширения макросов.
Аргументы функционального макроса полностью раскрываются перед вставкой в текст замены макроса, за исключением случаев, когда они являются операндами строкового преобразования (#
) или вставка токена (##
) оператор. Поэтому, если вы вызываете inner_LOAD_ATOM(buffer, ATOM_MAX)
непосредственно, ATOM_MAX
не расширяется до #
оператор применяется.
С другой стороны, когда вы вызываете LOAD_ATOM(buffer, ATOM_MAX)
, ATOM_MAX
макрос раскрывается раньше LOAD_ATOM()
расширен. inner_LOAD_ATOM()
не учитывается в этой точке - это просто часть текста замены внешнего макроса до LOAD_ATOM()
Расширение пересматривается для дальнейшего расширения макросов.
Потому что на первом проходе #y
будет заменен #ATOM_MAX
и зачеркнутый. Так что это не будет расширено на втором проходе. Давайте просто запустим его вручную:
Первый проход:
int main(void)
{
char buffer[10] = {0, };
/* wrapped works fine */
inner_LOAD_ATOM(buffer, 10); // <-- Note - here it ATOM_MAX was expanded in the first pass
/* [Warning] unknown conversion
type character 'A' in format [-Wformat=] */
scanf("%" "ATOM_MAX" "s", buffer);
printf("%s\n", buffer);
return 0;
}
Второй проход:
int main(void)
{
char buffer[10] = {0, };
/* wrapped works fine */
scanf("%" "10" "s", buffer);
/* [Warning] unknown conversion
type character 'A' in format [-Wformat=] */
scanf("%" "ATOM_MAX" "s", buffer); // <----- Not expanded as is interpreted as string
printf("%s\n", buffer);
return 0;
}