定义一个函数,它 returns 一个函数指针,它也是 returns 一个没有 typedef 的函数指针

Defining a function which returns a function pointer which also returns a function pointer without typedefs

我试图在不使用 typedef 的情况下真正理解函数指针,但似乎无法理解。我不明白需要什么签名来传达我 return 指向函数指针的指针。

#include <stdio.h>

void odd()  { printf("odd!\n");  }
void even() { printf("even!\n"); }

void (*get_pfn(int i))()
{
    return i % 2 == 0 ? &even : &odd;
}

__SIGNATURE__
{
    return &get_pfn;
}

int main()
{
    get_pfn_pfn()(1)();
    get_pfn_pfn()(2)();
    return 0;
}

要完成这项工作,__SIGNATURE__ 必须是什么?

是这样的:

void (*(*get_pfn_pfn(void))(int))()

函数 get_pfn 的 return 类型是 -

void (*) ();

所以 &get_pfn 的类型是 -

void (*(*)(int))()

现在,这个函数 return 是这种类型,因此它的签名将是 -

void (*(*(foo)())(int))()

您可以通过在 cdecl.org

中输入来验证这一点

它必须 return 一个函数指针指向一个接受 int 和 return 函数指针的函数:

void (*(*get_pfn_pfn(void))(int))(void) {
    return &get_pfn;
}

更多行:

void (*
        (*
             get_pfn_pfn(void)  // this is our function
        )(int i) // this is get_pfn(int)
     )(void)  // this is odd() or even()
{
    return &get_pfn;
}

可以省略void,在这种情况下,函数指针指向一个参数数量未知的函数。这不是你想要的。要声明一个指向不带参数的函数的函数指针,您应该在函数参数列表中添加 void 。同理最好把get_pfn改成void (*get_pfn(int i))(void)。例如尝试从 get_pfn(1)("some arg", "some other arg"); 呼叫。 C 编译器不会给出警告,因为空的 () 表示 unknown 参数。要说函数不带参数,你必须 (void).

对于许多大括号序列,尤其是))(,在函数指针中很难解析。这就是为什么许多人更喜欢函数指针或类型的类型定义:

typedef void get_pfn_func_t(void);    
get_pfn_func_t *get_pfn(int i) {
    return i % 2 == 0 ? &even : &odd;
}

typedef get_pfn_func_t *get_pfn_pfn_func_t(int i);
get_pfn_pfn_func_t *get_pfn_pfn(void) {
    return &get_pfn;
}

没有 typedef 的函数指针可能很难处理。要弄清楚它们,您需要从内到外工作。

那么让我们详细分析一下我们是如何得出正确的函数签名的。

get_pfn_pfn是一个函数:

get_pfn_pfn()

不带参数:

get_pfn_pfn(void)

和returns一个指针:

*get_pfn_pfn(void)

到一个函数:

(*get_pfn_pfn(void))()

需要一个 int 参数:

(*get_pfn_pfn(void))(int)

和returns一个指针:

*(*get_pfn_pfn(void))(int)

到一个函数:

(*(*get_pfn_pfn(void))(int))()

不带参数:

(*(*get_pfn_pfn(void))(int))(void)

而returns什么都没有(即void):

void (*(*get_pfn_pfn(void))(int))(void)

当然,使用 typedef 可以大大简化这一过程。

首先是 evenodd 的类型:

typedef void (*func1)(void);

然后我们可以将其应用于 get_pfn:

func1 get_pfn(int) { ... }

那么这个函数的类型:

typedef func1 (*func2)(int);

我们可以申请get_pfn_pfn:

func2 get_pfn_pfn(void) { ... }