将具有不同指针类型参数的函数指针进行强制转换

4
#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
}

一个函数指针 void(*)(A*) 被转换为一个函数指针 void(*)(void*)。然后它被调用时带有参数类型为 A*
当直接使用时,是否可以保证其正确工作 (1)?还是需要像 (2) 一样进行转换回去?

2
这是未定义行为。 - tstanisl
1个回答

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

一个类型为T1的函数指针可以被转换成另一个类型为T2的函数指针,其中T2和T1的返回类型和参数类型都可以不同。转换后得到的函数指针可以通过强制类型转换再转回原来的类型,且其值不变。

方法1

pf(&a); // 1

不行。这是未定义的行为,不能保证可行。根据C11标准, 6.3.2.3p8

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

方法2

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

它是好的和定义的。因为函数签名为void(A*)的函数是通过指向void(A*)的指针调用的。

编辑

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

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

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


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