C 和 C++ 的联合函数指针初始化

Union function pointer initializing for both C and C++

如何在没有错误或警告的情况下使用函数指针初始化联合? 代码是针对嵌入式的,必须用C和C++编译。

但是,我遇到的问题是,直接初始化会产生与 C 不兼容的指针警告和 C++ 中的错误,而指定初始化已在 C++ 中弃用。

有没有办法在 C 和 C++ 中没有警告和错误地执行此操作?

最小示例:

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
 */
},

};

该代码确实适用于警告 incompatible pointer typesdesignated initializers are a C99 feature

粗略的方法是放弃联合并使用空指针。但是,由于明显的缺点,这远远低于我的首选选项。

alinsoar 正确评论。确保调用正确的函数是当前示例中省略的 List 中其他元素的工作。


指定初始化将在 C++20 中再次完全可用。
在那之前它们没有效果。除了他们似乎仍在工作的工会。 (减去警告)

在 C++ 中(C++20 之前)初始化第一个联合成员以外的联合成员的唯一方法是联合中的构造函数。

除了第一个 C 中的第一个联合成员之外,唯一的初始化方法是指定初始化器。

这不会留下很大的回旋余地。小心,丑陋的前方:

// 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

不是很好,但有一些可能性。 C++ 具有构造函数重载。 C 有 _Generic 和指定的初始值设定项。

typedef int foo_t (int num, int data);
typedef int fee_t (int num, float data);

typedef struct List
{
  union 
  {
    foo_t* foo;
    fee_t* fee;
  };

  #ifdef __cplusplus
    List(foo_t* f) :foo(f){}
    List(fee_t* f) :fee(f){}  

    #define FOO_INIT(f) List(f)
    #define FEE_INIT(f) List(f)
  #else
    #define FOO_INIT(f) { .foo = _Generic((f), foo_t*: (f)) }
    #define FEE_INIT(f) { .fee = _Generic((f), fee_t*: (f)) }
  #endif   
} List;

int the_foo (int num, int data){ return 0;}
int the_fee (int num, float data){ return 0;}

int main (void)
{
  List list_foo = FOO_INIT(the_foo);
  List list_fee = FEE_INIT(the_fee);
  return 0;
}

在任何一种语言中,这都应该是类型安全的。