一对指向不同函数的指针可以兼容不同类型的参数吗?

xiv*_*r77 5 c function-pointers undefined-behavior language-lawyer

我们可以将特定签名的函数地址放入函数指针中,该函数指针被定义为具有其他签名并无缝使用吗?

例如,以下代码

#include <stdio.h>

void print_n(int *pn) {
    printf("%d\n", *pn);
}

void print_n_wrapper(void *p) {
    print_n(p);
}

int main(void) {
    int n = 123;
    void (*f)(void *) = print_n_wrapper;
    f(&n);
    f = print_n;
    f(&n);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

得到编译并在我的机器上运行良好.我是以某种方式调用未定义的行为吗?

Sou*_*osh 8

是的,这是未定义的行为.

引用C11,章节§6.3.2.3,指针,(强调我的)

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

关于"类型不兼容的功能"部分,兼容性的定义如下

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

这意味着,void *int * 应该是相同的类型,但它们都没有.因此,这些功能也不兼容.


Bat*_*eba 6

要在通话print_n(p)print_n_wrapper 定义的,因为所有你正在做的是转换void*其最初是int*一个int*

作业f = print_n;会给你带来麻烦.虽然分配规定,对后续调用的行为f(&n) 不确定的.