C 将函数转换为函数指针

C 将函数转换为函数指针,c,C,在一个遗留项目中发现了这段代码,这种类型的转换在c中有效吗 编辑:调用函数ptr否,它无效。调用方期望的原型与被调用函数的原型不匹配,因此可能导致未定义的行为。具体的结果将取决于编译器和调用约定等因素(被调用函数可能只会在arg中看到垃圾,或者线程堆栈可能会损坏,从而导致崩溃)。Andrew Medico说它无效是对的,但在实际操作中,它肯定会在当前绝大多数ABI上工作,并且工作可靠 现在使用的大多数ABI都允许调用者在寄存器中执行所有堆栈维护和/或传递参数,因此,如果您为函数提供的参数超过其要

在一个遗留项目中发现了这段代码,这种类型的转换在c中有效吗


编辑:调用函数ptr

否,它无效。调用方期望的原型与被调用函数的原型不匹配,因此可能导致未定义的行为。具体的结果将取决于编译器和调用约定等因素(被调用函数可能只会在
arg
中看到垃圾,或者线程堆栈可能会损坏,从而导致崩溃)。

Andrew Medico说它无效是对的,但在实际操作中,它肯定会在当前绝大多数ABI上工作,并且工作可靠

现在使用的大多数ABI都允许调用者在寄存器中执行所有堆栈维护和/或传递参数,因此,如果您为函数提供的参数超过其要求的数量,没有人会注意到。您只需要拥有一些未使用的堆栈空间,或者将一个值写入一个从未使用过的寄存器

实际上,你也可以做相反的事情;也就是说,给一个函数提供的参数比它要求的少。它将为这些参数接收未定义的值,但如果它不使用它们,您就可以了。事实上,标准的POSIX C函数
open()
依赖于这种行为,这表明无论是现在还是过去,C ABI被这些东西阻塞是多么罕见

如果可能的话,你当然应该避免依赖这种行为来工作,但特别是如果你不在乎过于便携的话,我真的看不出有什么理由对此犹豫不决。然而,你应该非常清楚自己在做什么,如果你觉得自己不了解这些技巧可能有效或无效的原因,就不应该使用这些技巧


一种情况是,如果您正在用Pascal/BASIC(如ABI)(如Windows上的
stdcall
)编写函数,调用者设置堆栈,但被调用者将其清除。在这种情况下,调用者将推送两个参数,但被调用者只弹出一个参数,因此堆栈指针在返回后将与其调用前的值不匹配,这将导致各种奇怪的情况,包括但不限于调用者函数在返回时未使用正确的返回地址。崩溃是有保证的。然而,在C语言中这样做是很不寻常的。

不,不是。如果参数的数量是关闭的,那么至少在Win32代码(stdcall)中会有一个巨大的混乱。它在标准C中无效,但在某些实现中可能会起作用。7系统寄存器输入不会回调?有效的方法是什么?取决于情况。可能会将函数指针传递给需要该签名的函数,或者使用调用该函数的兼容签名创建包装器(传递可用参数并为另一个参数提供一些值)。
typedef void (*LoopCallback)(int fd, void * arg);

LoopCallback func_ptr = 0;

void call_back(int value)
{
    printf("%d", value);
}

void sys_register_input(LoopCallback call_back)
{
    func_ptr = call_back;
}

int main()
{
    sys_register_input((LoopCallback)call_back);
    func_ptr(33, 0);
}