初始化函数指针数组时为什么需要“警告”?

9

我尝试初始化一个函数指针数组,但是出现了“警告”:

ring-buffer.c:57:19: warning: assignment from incompatible pointer type [enabled by default]
RBufP->rbfunc[0] = &RBufPush;
                 ^

但这个社区还好。
/*typedef for func pointer*/
typedef RBRetCod_t (*RBFunc)();

/*RBufP*/
typedef struct {
    RBufSiz_t size; /*size and mask*/
    RBufDat_t rbufdat;
    RBufPoint_t head, tail;
    RBFunc rbfunc[3]; /*announce of function pointers array*/
} RBuf_t;
RBuf_t *RBufP;
...

/*init for func pointers array*/
RBufP->rbfunc[2] = &RBufDel; /*it is ok*/
RBufP->rbfunc[1] = &RBufPull; /*it is ok*/
RBufP->rbfunc[0] = &RBufPush; /*it is bad, why???*/

...

/*body of the functions*/
RBRetCod_t RBufPull(unsigned char *dat)
{
        return RBSUCC;
}
RBRetCod_t RBufDel(void)
{
        return RBSUCC;
}
RBRetCod_t RBufPush(unsigned char dat)
{
        return RBSUCC;
}

请解释一下为什么在这行代码中出现警告:RBufP->rbfunc[0] = &RBufPush;,而相邻的行却没有警告?


你能展示一下 RBufP 是如何定义的吗?如果还没有呈现出来,那么这种类型的结构是怎样的呢? - dhein
你使用的编译器是什么? - syntagma
1
函数类型没有参数是C语言中的一个旧特性,但具有一些奇怪的行为。请参见https://dev59.com/sGYr5IYBdhLWcg3wG2lI - Mats
@REACHUS 使用带有-Wall选项的gcc - Ivan Ivanovich
2
你真的需要使用一个数组吗?相反,你可以使用“结构体”,这样所有的函数指针都可以有正确的类型。 - user694733
显示剩余2条评论
2个回答

7
请参阅C11第6.7.6.3§14节,指定何时应将两个函数类型视为兼容:

[...] 如果一个类型具有参数类型列表,而另一个类型由不是函数定义的函数声明符指定,并且包含空标识符列表,则参数列表不得具有省略号终止符,而且每个参数的类型都必须与应用默认参数提升所得到的类型兼容。[...]

这适用于RBufPullRBufDel,但不适用于RBufPush,因为unsigned char会被提升为int

如果您通过RBFunc类型的指针调用RBuPush,则会将一个int参数推送到堆栈,而RBufPush则期望一个unsigned char。根据调用约定和字节序,您将获得不正确的结果。

一种解决方法是将RBufPush更改为接受int参数。另一种解决方法是使用强制转换,例如

RBufP->rbfunc[0] = (RBFunc)&RBufPush;

在调用rbfunc [0]之前,您需要将类型强制转换回正确的类型RBRetCod_t (*)(unsigned char)

5

来自ISO/IEC:9899:

J.5.7 函数指针转换

1 可以将指向对象或void的指针转换为指向函数的指针,从而允许数据被调用作为函数(6.5.4)。

2 可以将指向函数的指针转换为指向对象或void的指针,从而允许检查或修改函数(例如,通过调试器)(6.5.4)。

但是这个规则是有限制的:

6.3.2.3 指针

[...]

8 一个类型为函数指针的指针可以转换为另一种类型的函数指针,然后再转换回来;结果应该与原始指针相等。如果使用转换后的指针调用其指向的类型不兼容的函数,则行为是未定义的。

因此,您正在尝试使用相同的Pointerobject类型访问不同的函数。这是未定义的行为,因此警告是正确的。

注意:

在我看来,您尝试实现的功能类似于C#中的接口。

但是,在C中没有这种功能。


@IvanIvanovich:你到底在说什么?对不起,我不明白你在说什么。 - dhein
1
请注意,由于空参数列表的工作方式,仅在RBufPush的情况下才存在UB,而不是RBufPullRBufDel - Christoph
@Christoph:你说得对,你的回答比我的好。+1 给你。 - dhein

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接