使用不同指针类型的参数转换函数指针

tml*_*len 4 c casting function-pointers

#include <stdio.h>

typedef struct {
    int i;
} A;

void f(A* a) {
    printf("%d\n", a->i);
}

int main() {
    void (*pf)(void*) = (void(*)(void*))&f;
    A a;
    pf(&a); // 1
    ((void(*)(A*))pf)(&a); // 2
}
Run Code Online (Sandbox Code Playgroud)

函数指针void(*)(A*)被强制转换为函数指针void(*)(void*)。然后使用类型为 的参数调用它A*

直接使用是否能保证正常工作(1)?还是需要像(2)那样将其投射回来?

tst*_*isl 13

首先。C11 标准 6.3.2.3p8允许指向具有不同签名的函数的指针之间的转换

指向一种类型函数的指针可以转换为指向另一种类型函数的指针,然后再转换回来;结果应等于原始指针。

方法一

pf(&a);// 1

不。这是未定义的行为,并且不能保证有效。来自C11 标准,6.3.2.3p8

...如果转换后的指针用于调用其类型与引用类型不兼容的函数,则行为未定义。

方法二

((void(*)(A*))pf)(&a);// 2

它很好而且很明确。因为带有签名的函数void(A*)是通过指向 的指针调用的void(A*)

编辑

函数类型的兼容性在6.7.6.3p15中定义:

为了使两个函数类型兼容,两者都应指定兼容的返回类型。此外,参数类型列表(如果两者都存在)应在参数数量和省略号终止符的使用方面一致;相应的参数应具有兼容的类型。...

函数void(void*)void(A*)不兼容,因为类型void*A*不兼容。