11

如何声明可以安全地指向任何函数的函数指针?

我需要void指针之类的东西,但对于函数。我想过简单地使用它,但是根据这个问题的答案,函数指针不能可靠地转换为数据指针,至少在非 POSIX 系统上是这样。

我搜索并找到了一些可能的例子:

  • Windows 有FARPROC

    int (FAR WINAPI * FARPROC) ()
    

    该文档还提到了这一点:

    在 C 中,FARPROC 声明表示具有未指定参数列表的回调函数。

    听起来不错,但是返回值呢?它明确指定为int

  • OpenGL 的规范之一具有:

    typedef void (*GLfunction)();
    extern GLfunction glXGetProcAddressARB(const GLubyte *procName);
    

    参数列表也未指定,但返回类型明确指定为void

我不确定如何解释这一点。在使用之前,函数指针将被转换为具有适当原型的函数指针类型。例如:

typedef void (*function_pointer_t)();
extern function_pointer_t get_function(const char * name);

/* Somewhere else... */

typedef double (*cosine_function_t)(double);
cosine_function_t cosine = (cosine_function_t) get_function("cos");

这段代码安全吗?它是否违反任何 C 标准或导致任何未定义的行为?

4

2 回答 2

13

首先,没有办法声明一个函数指针,它能够在没有强制转换的情况下接受任何函数指针类型。正如您自己已经注意到的那样,问题是任何函数指针声明都会立即假定特定的返回类型。void *因此,在函数指针世界中没有完全类似的东西。

其次,只要您使用显式强制转换,任何函数指针都可以用于存储任何其他函数指针值。当然,为了通过强制转换为不同类型的指针执行正确的调用,您需要将其转换回原始类型。即,只要在调用时恢复了正确的函数指针类型,这不会导致任何未定义的行为。

在您的示例中,如果返回的指针get_function确实指向double (double)类型的函数,那么通过cosine指针调用该函数是完全安全的。指针值中间存储在void (*)()指针中的事实不会破坏它。

第三,在 C 语言中,()参数声明代表未指定数量和类型的参数。这是朝着“通用”函数指针类型方向迈出的一步,可以在没有强制转换的情况下使用(只要您在调用中提供正确的参数并且返回类型匹配)

void foo(void);
void bar(int i);
void baz(long i, double x);

int main() {
  void (*a[3])() = { foo, bar, baz };
  a[0]();
  a[1](42);
  a[2](5L, 3.1415);
}

但是,返回类型的问题仍然存在。

于 2012-10-06T19:26:58.553 回答
5

您可以使用联合。通过这个指针调用的函数类型肯定是有限的,你可以把它们都放在联合中。

于 2012-10-06T19:48:24.810 回答