Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Union function pointer initializing for both C and C++

How to initialize a union with function pointers without errors or warnings? The code is targeted at embedded and have to compile it both in C and C++.

However I face the problem that direct initializing yields an warning of incompatible pointers with C and an error in C++ while designated initialization has been deprecated in C++.

Is there any way to do this without warnings and errors in C and C++?

Minimal example:

struct List {
    union {
        int (*foo)(int num, int data);
        int (*fee)(int num, float  data);
    };
};

int foo_fun(int pnum, int data);
int fee_fun(int pnum, float  data);

static const struct List list[] = {
{
    {foo_fun},
},

{
    {fee_fun},
/* C = warning: incompatible pointer types initializing 'int (*)(int, int)'
 * with an expression of type 'int (int, float)'
 */
/* C++ = error: cannot initialize a member subobject of type 'int (*)(int, int)'
 * with an lvalue of type 'int (int, float)':
 * type mismatch at 2nd parameter ('int' vs 'float')
 */
},

/* With C++ */
{
    {.fee = fee_fun},
/*   ^^^^^^^^^^^^^
 * C++ = warning: designated initializers are a C99 feature
 */
},

};

The code does work with the warnings incompatible pointer types or designated initializers are a C99 feature.

The crude way is to drop the union and use a void pointer. However, that is far down my list of preferred options due to obvious drawbacks.

Correctly remarked by alinsoar. Making sure the correct function is called is the job of other elements in List currently omitted in the example.


Designated initializes will become fully available again in C++20.
Until then they have no effect. Except for unions where they still seem to work. (minus the warning)

like image 207
Jeroen3 Avatar asked Sep 24 '26 06:09

Jeroen3


1 Answers

The only way to initialize a union member beyond the first in C++ (before C++20) is a constructor in the union.

The only way to initialize a union member beyond the first in C is a designated initializer.

This doesn't leave a whole lot of wiggle room. Beware, ugliness ahead:

// For convenience
typedef int (*fooPtr)(int, int);
typedef int (*feePtr)(int, float);


#ifndef __cplusplus
#define INITIALIZE(x) .x =
#else
#define INITIALIZE(x)
#endif


struct List {
    union X {
#ifdef __cplusplus
        constexpr X(fooPtr foo_) : foo(foo_) {}
        constexpr X(feePtr fee_) : fee(fee_) {}
#endif
        fooPtr foo;
        feePtr fee;
    } x;
};

int foo_fun(int pnum, int data);
int fee_fun(int pnum, float  data);

static const struct List list[] = {
    {
        {INITIALIZE(foo) foo_fun},
    },
    {
        {INITIALIZE(fee) fee_fun},
    },
};

https://godbolt.org/z/pd42HT

like image 127
Max Langhof Avatar answered Sep 25 '26 20:09

Max Langhof