Макрос переводит идентификатор предыдущего макроса вместо его замены

Почему 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;
}
Другие вопросы по тегам