1

Why is inner_LOAD_ATOM(buffer, ATOM_MAX) converted to scanf("%" "ATOM_MAX" "s", x) but the wrapped version isnt? I would expect ATOM_MAX(identifier) to be replaced by 10 before it is "passed" to inner_LOAD_ATOM or LOAD_LINE and making the wrapper useless. More elaborated answer why the wrapper is necessary would be very appreciated.

#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;
}
Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
Pruzo
  • 87
  • 1
  • 8

2 Answers2

2

It's important to understand that function-like macros don't work like C functions. There is (almost) no sense of a macro call stack or of forwarding arguments from one macro to another. Instead, macro expansion proceeds iteratively -- macro is replaced with its expansion, then the expansion is rescanned for further macros to expand.

A function-like macro's arguments are completely macro expanded before being inserted into the macro's replacement text, except where they are the operands of the stringification (#) or token-pasting (##) operator. Therefore, if you invoke inner_LOAD_ATOM(buffer, ATOM_MAX) directly, ATOM_MAX is not expanded before the # operator is applied.

On the other hand, when you invoke LOAD_ATOM(buffer, ATOM_MAX), the ATOM_MAX macro is expanded before LOAD_ATOM() is expanded. The inner_LOAD_ATOM() doesn't factor in at that point -- it's just part of the outer macro's replacement text until LOAD_ATOM()'s expansion is re-scanned for further macro expansions.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
1

Because on the first pass #y will get replaced by #ATOM_MAX and stringified. So it won't get expanded on the second pass. Let's just run it manually:

First pass:

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;
}

Second pass:

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;
}
Eugene Sh.
  • 17,802
  • 8
  • 40
  • 61