Search code examples
cmacros

Issue in expanding variadic MACRO


I have the following piece of code in C which works flawlessly. I define NAME_LIST to facilitate the creation of NAMES_TABLE.

#include <stdio.h>
#include <stdint.h>

typedef enum {
    NAME_1 = 0,
    NAME_2 = 1,
    NAME_3 = 2,
    NAME_4 = 3,
} name_t;

typedef struct {
    const uint8_t num_names;
    const name_t *name_list;
} name_struct_t;

#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

#define NAME_LIST(...) { \
    .num_names = ARRAY_SIZE(((name_t[]){__VA_ARGS__})), \
    .name_list = (name_t[]){__VA_ARGS__} \
}

name_struct_t NAMES_TABLE[] = {
    NAME_LIST(NAME_1),
    NAME_LIST(NAME_2, NAME_3),
    NAME_LIST(NAME_4),
};

I want to expand the previous code and add a fixed input argument in the NAME_LIST MACRO to indicate as specific state to be handled later in the code.

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>

typedef enum {
    NAME_1 = 0,
    NAME_2 = 1,
    NAME_3 = 2,
    NAME_4 = 3,
} name_t;

typedef struct {
    const uint8_t num_names;
    const name_t *name_list;
    const bool flag;
} name_struct_t;

#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

#define NAME_LIST(flag, ...) { \
    .num_names = ARRAY_SIZE(((name_t[]){__VA_ARGS__})), \
    .name_list = (name_t[]){__VA_ARGS__} \
    .flag = (bool)(flag) \
}

name_struct_t NAMES_TABLE[] = {
    NAME_LIST(true, NAME_1),
    NAME_LIST(false, NAME_2, NAME_3),
    NAME_LIST(true, NAME_4),
};

However, I get the following errors which I am not able to solve.

main.c:36:19: error: expected identifier before numeric constant
   36 |         NAME_LIST(true, NAME_1),
      |                   ^~~~
main.c:32:10: note: in definition of macro ‘NAME_LIST’
   32 |         .flag = (bool)(flag) \
      |          ^~~~
main.c:37:19: error: expected identifier before numeric constant
   37 |         NAME_LIST(false, NAME_2, NAME_3),
      |                   ^~~~~
main.c:32:10: note: in definition of macro ‘NAME_LIST’
   32 |         .flag = (bool)(flag) \
      |          ^~~~
main.c:38:19: error: expected identifier before numeric constant
   38 |         NAME_LIST(true, NAME_4),
      |                   ^~~~
main.c:32:10: note: in definition of macro ‘NAME_LIST’
   32 |         .flag = (bool)(flag) \
      |          ^~~~

Any idea if the extension of the MARCO definition that I did is correct or if there is an alternative way to do that?


Solution

  • It does not like that you use flag for the macro parameter and the struct member at the same time. Renaming one of them to something different and adding the missing comma after .name_list = (name_t[]){__VA_ARGS__} make it work:

    #include <stdio.h>
    #include <stdint.h>
    #include <stdbool.h>
    
    typedef enum {
        NAME_1 = 0,
        NAME_2 = 1,
        NAME_3 = 2,
        NAME_4 = 3,
    } name_t;
    
    typedef struct {
        const uint8_t num_names;
        const name_t *name_list;
        const bool flag;
    } name_struct_t;
    
    #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
    
    #define NAME_LIST(xyz, ...) { \
        .num_names = ARRAY_SIZE(((name_t[]){__VA_ARGS__})), \
        .name_list = (name_t[]){__VA_ARGS__}, \
        .flag = (bool)(xyz) \
    }
    
    name_struct_t NAMES_TABLE[] = {
        NAME_LIST(true, NAME_1),
        NAME_LIST(false, NAME_2, NAME_3),
        NAME_LIST(true, NAME_4),
    };