user1806687
user1806687

Reputation: 920

Initializing correct union member based on compile time evaluation

I want to initialize different union member depending if a macro expression is a constant or a variable.

So far I've found GCC extension __builtin_constant_p() which evaluates an expression and returns 1 if it is a constant and 0 otherwise. Which is exactly what I need. However I have yet to found a way how to initialize different union members based on this information.

Below is the code example:

#define TOKEN 10

typedef union 
{
    void* pv_variable;
    int literal;
} foo_t;

foo_t test_array[] =
{
    {.literal = 500},
    {.pv_variable = NULL}

    // Below doesnt work. How to make it work??
    //
    // {(TOKEN == 10) ? (.literal) : (.pv_variable) = 10},
    // {__builtin_choose_expr(__builtin_constant_p(TOKEN), .literal = 10, .pv_variable = NULL)},
    // {. ## __builtin_choose_expr(__builtin_constant_p(TOKEN), literal, pv_variable) = 10},
};

EDIT: Clarification on what I want to accomplish is detailed below.

#define INIT_UNION(val) /* TODO: */
#define SOME_VARIABLE some_variable
#define SOME_CONSTANT 10

int some_variable = 20;

typedef union 
{
    void* pv_variable;
    int literal;
} foo_t;

foo_t test_array[] =
{
    INIT_UNION(SOME_CONSTANT), /* should produce: {.literal = 10} */
    INIT_UNION(SOME_VARIABLE)  /* should produce: {.pv_variable = &some_variable} */
};

Upvotes: 1

Views: 114

Answers (1)

Tenobaal
Tenobaal

Reputation: 835

Your first idea was pretty close:

#define TOKEN 10

typedef union foo_u
{
    void* pv_variable;
    int literal;
} foo_t;

#define INIT_FOO_T(val) (__builtin_constant_p(val) ? (foo_t) {.literal = val} : (foo_t) {.pv_variable = val})

foo_t test_array[] =
{
    {.literal = 500},
    {.pv_variable = NULL},
    INIT_FOO_T(TOKEN)
};

Unfortunately you can use #if inside a #define, so this is the only way.

Maybe instead of:

#define INIT_FOO_T(val) (__builtin_constant_p(val) ? (foo_t) {.literal = val}

you mean:

#define INIT_FOO_T(val) (__builtin_constant_p(val) ? (foo_t) {.literal = &val}

this would make more sense but requires a different approach (it won't work anymore).

EDIT: you want the second case

#if __builtin_constant_p(TOKEN)
foo_t test_array[] =
{
    {.literal = 500},
    {.pv_variable = NULL},
#if __builtin_constant_p(TOKEN)
    {.literal = TOKEN},
#else
    {.pv_variable = &TOKEN},
#endif
};

Unfortunately I don't know how you can build a macro to do this for you.

Upvotes: 1

Related Questions