将 foo(int *) 作为参数传递给 X 中的 foo(void*)

问题描述

A 有一个功能

void somefunc(void func(void *)) { ... }

void foo(int *num) {...} 

我试图将 foo 作为参数传递给 somefunc 但收到警告。 这样做的正确方法是什么?

解决方法

具有一个带有一个或多个 void * 参数的函数的参数是实现某些类型泛型算法的常用方法。 (此答案假设此代码中的情况如此。其他可能性存在但不太可能。) funcsomefunc 的参数提供了 somefunc 用于对数据进行操作的回调函数不知道它的类型。

请注意,虽然参数声明为函数 void func(void *),但它会自动调整为指向函数 void (*func)(void *) 的指针。除去名称,我们得到抽象类型 void (*)(void *)

您不能为 void (*)(int *) 参数传递 void (*)(void *) 参数,因为它们是不兼容的类型。并且您不应该尝试通过强制转换将 foo 参数强制转换为参数类型,因为使用转换后的指针调用 void (int *) 函数的行为不是由 C 标准定义的。正确的解决方案是将指针传递给预期类型的​​函数。您可以为此创建一个新函数:

void FooWrapper(void *p) { foo(p); }

然后您可以将 FooWrapper 传递给 somefunc。当 somefunc 调用 FooWrapper 时,它会传递一个 void *。当 FooWrapper 调用 foo 时,该 void * 将自动转换为 int *。 (大概,foo 是预先声明的,带有原型。)只要 void * 传递的 FooWrapper 起源于指向某个 int 的指针,这种从 {{ 1}} 回到 void * 是由 C 标准定义的,所以这是正确的代码。

或者,您可以修改 int * 以获取 foo 参数并将其在内部转换为 void *,而不是创建包装器:

int *

然后您可以将 void foo(void *VoidNum) { int *num = VoidNum; … } 直接传递给 foo

,

我试图将 foo 作为参数传递给 somefunc 但收到警告。

发生错误是因为 somefunc 被声明为期望类型为 void (*)(void *) 的参数,但传递的参数 foo 的类型为 void (*)(int *)。这两种类型不同且不兼容。

这样做的正确方法是什么?

函数指针可以在不同类型之间转换,所以下面的编译不会出错。

void bar()  { somefunc((void (*)(int *))foo); }

使用辅助 typedef 使相同的代码更具可读性。

typedef void (*VOID_FUNC)(void *);

void bar()  { somefunc((VOID_FUNC)foo); }

重要的警告是,唯一合法/安全地使用 func 中的 somefunc 参数是将其转换回真实的使用原始函数之前的类型。来自语言标准中的相关段落 6.3.2.3/8:“指向一种类型函数的指针可以转换为指向另一种类型函数的指针,然后再返回;结果应与原始值相等指针。 如果使用转换后的指针调用类型与引用类型不兼容的函数,则行为未定义。"

以下是正确用法的缩写示例。

extern int n;
void foo(int *num);

typedef void (*VOID_FUNC)(void *);
typedef void (*INT_FUNC)(int *);

void somefunc(VOID_FUNC func)  { ((INT_FUNC)func)(&n); }

void bar()  { somefunc((VOID_FUNC)foo); }