首页 > 解决方案 > 在 C 中创建一个通用的“函数指针”联合是一个坏主意吗?

问题描述

对于我正在从事的项目,最好有一个通用的“指向函数的指针”类型。但是,在 C 中,要拥有指向函数的指针,您需要在函数指针的类型中指定原型。

例如,如果我有 function void setdata(short data),我不能将它存储在与 function 相同的指针中int getdata(),因为它们的参数和返回值是不同的。

经过一番横向思考,我想出了以下解决方法:

typedef long (* PFL)(); /* pointer to function that returns a long... */
typedef short (* PFI)(); /* pointer to function that returns a short... */
typedef void (* PFV)(); /* pointer to function that returns a void... */
typedef void (* PFVAL)(long); /* pointer to function that returns a void...
                                but has a long argument...*/
typedef void (* PFVAI)(short); /* pointer to function that returns a void...
                                but has an short argument...*/
typedef void (* PFVAU)(unsigned short);
typedef void (* PFVAII)(short, short); /* same as above, but two shorts... */
typedef void (* PFVAUU)(unsigned short, unsigned short); /* same as above, but two shorts... */

typedef union {
    PFV         pfv;
    PFI         pfi;
    PFL         pfl;
    PFVAL       pfval;
    PFVAI       pfvai;
    PFVAU       pfvau;
    PFVAII      pfvaii;
    PFVAUU      pfvauu;
} FP;

果然,我可以像这样初始化这种类型的实例:

FP funcpointer = { .pfvai = setdata };

Clang 和 GCC 不会抱怨。这是一个坏主意吗?

标签: cpointersunionfunction-pointerstypedef

解决方案


你在做什么是有效的。只要您通过正确的指针类型调用指向的函数,它就被很好地定义了。

然而,这个联合可能会变大,这取决于您必须支持多少不同的函数类型,并且您必须使其与您的 typedef 集保持同步。事实证明,您可以通过强制转换自由地将一种函数指针类型转换为另一种,您只需要确保使用正确的类型调用它。

C 标准的第 6.3.2.3p8 节对函数指针转换进行了如下说明:

指向一种类型的函数的指针可以转换为指向另一种类型的函数的指针,然后再返回;结果应与原始指针比较。如果转换后的指针用于调用类型与引用类型不兼容的函数,则行为未定义。

因此,您也可以仅将void (*)()其用作通用指针类型而不是使用联合,然后在调用它时需要应用正确的强制转换。例如:

typedef void (*FP)();
FP fp = setdata;
...
((PFVAI)fp)(123);

推荐阅读