为什么在初始化函数指针数组时会出现"警告"?

Iva*_*ich 9 c arrays pointers function-pointers function

我尝试初始化一个函数指针数组,我有"警告":

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

但邻居还可以:

/*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;
}
Run Code Online (Sandbox Code Playgroud)

请向我解释为什么警告发生在这一行:RBufP->rbfunc[0] = &RBufPush;,但相邻的行不存在?

Chr*_*oph 7

参见C11第6.7.6.3节第14节,规定何时应将2种功能类型视为兼容:

[...]如果一种类型的具有参数类型列表,并通过函数声明是不是一个函数定义的一部分指定的其它类型和包含一个空标识列表,参数列表不应有省略号终止子和所述每个参数的类型应与应用默认参数促销产生的类型兼容.[...]

出现这种情况的RBufPullRBufDel,而不是RBufPush因为unsigned char被晋升为int.

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

一种解决方案是改变RBufPush以进行int论证.另一个是使用演员表,即

RBufP->rbfunc[0] = (RBFunc)&RBufPush;
Run Code Online (Sandbox Code Playgroud)

RBRetCod_t (*)(unsigned char)在调用之前,您需要回送到正确的类型rbfunc[0].


dhe*_*ein 5

来自ISO/IEC:9899:

J.5.7函数指针强制转换

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

2指向函数的指针可以强制转换为指向对象或无效的指针,允许检查或修改函数(例如,通过调试器)(6.5.4).

但这条规则受到限制:

6.3.2.3指针

[...]

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

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

注意:

在我看来,你试图实现的将是一个类似于界面的东西C#.

但是C中没有这种功能