cmacrosx-macros

Expand X macro inside another macro


I have a function that prints an output using fprintf(), and it uses a macro both for the format string and the parameters. Since there are several places printing this info, this allows expanding the print while changing only one place.

I want to generate a different print using the same data, but I want them to automatically expand together using an X-macro, but I can't get it to compile. I don't want there to be a need to edit the print every time I add something to print, or to wrap each print in ugly #defines.

This program attempts to do what I want, but it doesn't compile:

#include <stdio.h>

#define X(_a, _b, _c) \
    _a,

#define TABLE \
    X("abc", "123", "ddd") \
    X("def", "456", "aaa") \
    X("ghi", "789", "ddd") \
    
#define STUFF \
    TABLE

#undef X
    
int main()
{
    printf(" %s %s %s\n", STUFF);

    return 0;
}

(Idea is that STUFF prints one thing, and at another place i'll do a STUFF2 with a different column of the X macro called TABLE)

I get the following error:

main.c: In function ‘main’:

main.c:7:5: warning: implicit declaration of function ‘X’ [-Wimplicit-function-declaration]

X("abc", "123", "ddd") \

^

main.c:12:5: note: in expansion of macro ‘TABLE’

TABLE

^~~~~

main.c:18:27: note: in expansion of macro ‘STUFF’

printf(" %s %s %s\n", STUFF);

                      ^~~~~

main.c:8:5: error: expected ‘)’ before ‘X’

X("def", "456", "aaa") \

^

Solution

  • main.c:7:5: warning: implicit declaration of function ‘X’ [-Wimplicit-function-declaration]

    Well, yes. At line 18, where macro STUFF appears, it is first expanded to

    TABLE
    

    , then that is rescanned. TABLE being defined as a macro, it, too, is expanded, resulting in

    X("abc", "123", "ddd") X("def", "456", "aaa") X("ghi", "789", "ddd")
    

    , then that is rescanned. But X is not defined as a macro (or as anything else) at that point, because you previously undefined it. That leaves you with code that resembles three calls to an unknown function, without any kind of operator or separator between. It is invalid.

    Your X macro has to be defined appropriately at the place where it is expanded. It does not need to be defined at all at the place where it appears in another macro's expansion text. You seem to have that backward.


    As discussed in comments, the objective is to be able to define separate macros, for example STUFF and STUFF2 that expand TABLE to consistent results that differ from each other. This is as opposed to causing STUFF to expand as wanted by manipulating the definition of X.

    This can be accomplished by changing the definition of TABLE so that it is a function-like macro taking another macro name as an argument:

    #define TABLE(m) \
        m("abc", "123", "ddd") \
        m("def", "456", "aaa") \
        m("ghi", "789", "ddd")
    

    The macros STUFF and STUFF2 can then control the expansion by their choice of which macro name to pass to TABLE():

    #define X(_a, _b, _c) _a
    #define Y(_a, _b, _c) _b
    #define STUFF TABLE(X)
    #define STUFF2 TABLE(Y)