How to fill a pointer array without a function call and from a macro?

Foxy

I have a small recursive AST as follows:

enum ABC
{
    A,
    B,
    C
};

typedef struct abc_t
{
    enum ABC kind;
    union {
        struct a_
        {
            int x;
        } a_;
        struct b_
        {
            int y;
        } b_;
        struct c_
        {
            struct abc_t **array;
        } c_;
    } u;
} abc_t;

To simplify the constructions, I define fill macros:

#define ABC_SET_A(n)    (abc_t) { .kind = A, .u.a_ = { n } }
#define ABC_SET_B(n)    (abc_t) { .kind = B, .u.b_ = { n } }

const abc_t bar = ABC_SET_A(5);
const abc_t foo = ABC_SET_B(2);

However, I don't know how to fill the "c_" branch of my AST with a macro. I would like to arrive at this result:

const abc_t test = ABC_SET_C({ABC_SET_B(4), ABC_SET_A(3), ABC_SET_B(2)});
// or
const abc_t test = ABC_SET_C(ABC_SET_B(4), ABC_SET_A(3), ABC_SET_B(2)); // With variadics arguments

The goal would be to have an immutable array of abc_t that would represent a set of pre-built structures, something like:

const abc_t pre_builds[] =
{
    ABC_SET_A(10),                            // pre_builds[0]
    ABC_SET_C({ABC_SET_A(8), ABC_SET_B(4)}),  // pre_builds[1]
    ABC_SET_B(23)                             // pre_builds[2]
    ...
};

I don't know how to handle a recursive structure for a such as macro, especially for an array in this case. How do I do it?

KamilCuk

First fix your ABC_SET_A and ABC_SET_B. You don't initialize int with braces like int var = { 1 }; , you initialize int like int var = 1;:

#define ABC_SET_A(n)    (abc_t){ .kind = A, .u.a_ = n }
#define ABC_SET_B(n)    (abc_t){ .kind = B, .u.b_ = n }

Doing your ABC_SET_C is easy. As you have array of pointers in your structure, you can do this:

#define ABC_SET_C(...)  (abc_t){ .kind = C, .u.c_ = (abc_t*[]) __VA_ARGS__ }
const abc_t pre_builds[] =
{
    ABC_SET_A(10),                            // pre_builds[0]
    // note - as this is array of pointers, I added & to get the pointer
    ABC_SET_C({&ABC_SET_A(8), &ABC_SET_B(4)}),  // pre_builds[1]
    ABC_SET_B(23)                             // pre_builds[2]
};

The { } braces are not special to preprocessor anyway and not parsed by it. I would prefer:

#define ABC_SET_C(...)  (abc_t){ .kind = C, .u.c_ = (abc_t*[]) { __VA_ARGS__ } }
const abc_t pre_builds[] =
{
    ABC_SET_A(10),                            // pre_builds[0]
    ABC_SET_C(&ABC_SET_A(8), &ABC_SET_B(4)),  // pre_builds[1]
    ABC_SET_B(23)                             // pre_builds[2]
};

If you want to get rid of writing & in front of every ABC_SET_*, then you can overload the macro on number of arguments and insert them per each argument. I find it not worth the effort, but it may be implemented like this for up to 3 arguments:

#define ABC_SET_A(n)    ((abc_t){ .kind = A, .u.a_ = n })
#define ABC_SET_B(n)    ((abc_t){ .kind = B, .u.b_ = n })
#define ABC_SET_C_1(_1)        &_1
#define ABC_SET_C_2(_1,_2)     &_1, &_2
#define ABC_SET_C_3(_1,_2,_3)  &_1, &_2, &_3
#define ABC_SET_C_N(_1,_2,_3,N,...)  ABC_SET_C##N
#define ABC_SET_C(...)  (abc_t){ .kind = C, .u.c_ = (abc_t*[]) { \
        ABC_SET_C_N(__VA_ARGS__,_3,_2,_1)(__VA_ARGS__) \
    } }

const abc_t pre_builds[] = {
    ABC_SET_A(10),                            // pre_builds[0]
    ABC_SET_C(ABC_SET_A(8), ABC_SET_B(4)),  // pre_builds[1]
    ABC_SET_B(23)                             // pre_builds[2]
};

Personally I don't like writing (abc_t) a compound literal in macro variable initialization. They make somethings like abc_t *arr = (abc_t[]){ ABC_SET_A(8) } impossible. I prefer leaving writing the &(abc_t) if needed to the user, so that others will know what is a pointer and what is not a pointer, so they know when and how the memory is allocated, what is the storage duration of the memory, etc. It also makes the macro easy to work in C++ and C99. Like this:

#define ABC_SET_A(n)    { .kind = A, .u.a_ = n }
#define ABC_SET_B(n)    { .kind = B, .u.b_ = n }
#define ABC_SET_C(...)  { .kind = C, .u.c_ = __VA_ARGS__ }
const abc_t pre_builds[] = {
    ABC_SET_A(10),                            // pre_builds[0]
    ABC_SET_C((abc_t*[]){ &(abc_t)ABC_SET_A(8), &(abc_t)ABC_SET_B(4) }),  // pre_builds[1]
    ABC_SET_B(23)                             // pre_builds[2]
};

// it also allows for something like the following naturally to work:
abc_t *make_me_visible_in_debugger[] = {
    &(abc_t)ABC_SET_A(8),
    &(abc_t)ABC_SET_B(4)
};
const abc_t pre_builds2[] = {
    ABC_SET_A(10),                            // pre_builds[0]
    ABC_SET_C(make_me_visible_in_debugger),  // pre_builds[1]
    ABC_SET_B(23)                             // pre_builds[2]
};

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Call function by function pointer from array of structs

How to fill pointer array from text file?

How to fill array in c? (assignment makes integer from pointer without a cast)

How to call a function from a function pointer?

Fill an array and then call a function

How to call a function from any class by a pointer to it?

C++ call function from inside a function with pointer array

How to use macro as function pointer?

How to fill Rust function pointer from C++

Call to a member function fill() on array

How to call a function by a pointer?

how to call pointer function

How can I call a macro from another worksheet without opening it?

How to pass function pointer (callback) and call it without knowing it's type?

Fill function pointer array in external files (C)

How to call a pointer to a member function which is retrieved from a map?

How to call a non-static method from a function pointer?

How to call a closure from a macro?

Pointer obejct function call without instantiating it

how to call function pointer in a struct?

how to call function to pointer of a class?

How to call function pointer in STL

How to Call a Function From a JSON Array

How to call a specific function from an array of functions?

Efficiently fill an array from a function

How to fill array of struct containing pointer arrays

How to call function from generic function without knowing the type?

How to quickly fill a numpy array with values from separate calls to a function

How can I fill a numpy structured array from a function?