【问题标题】:Circular function pointer question in CC中的循环函数指针问题
【发布时间】:2011-07-22 07:15:18
【问题描述】:

我试图弄清楚如何声明一个函数,该函数返回一个指向返回函数的函数的指针。这是一个循环问题,我不知道这是否可以在 c 中完成。这是我正在尝试做的一个说明性示例(它不起作用):

typedef (*)(void) (*fp)(void);

fp funkA(void) {
    return funkB;
}

fp funkB(void) {
    return funkA;
}

【问题讨论】:

  • “指向返回函数的函数的指针”——最后一个函数的签名是什么?

标签: c function pointers


【解决方案1】:

要在 C 中创建像这样的完全循环类型,您必须使用 struct(或 union)。在 C99 中:

typedef struct fpc {
    struct fpc (*fp)(void);
} fpc;

fpc funkB(void);

fpc funkA(void) {
    return (fpc){ funkB };
}

fpc funkB(void) {
    return (fpc){ funkA };
}

在 C89 中,你没有复合文字,所以你必须这样做:

fpc funkA(void) {
    fpc rv = { funkB };
    return rv;
}

fpc funkB(void) {
    fpc rv = { funkA };
    return rv;    
}

【讨论】:

  • 我现在不能试验它,但为什么 OP 解决方案不应该像你一样只添加 funkB 的原型,工作? (另一种方式:为什么我们需要包装指针?)
  • @ShinTakezou:因为可以定义为引用自身的唯一类型是 structunion(您需要一个 " 指向函数的指针,该函数返回指向函数返回一个指向函数的指针,返回一个指向函数的指针,返回......” - 这是一条试图吞下自己尾巴的蛇。
  • 我刚刚用 gcc 对其进行了测试,我需要将一个我尚未深入调查的警告静音,但它确实有效......我正在添加一个答案,仅供参考和分析
  • @ShinTakezou:通过使用强制转换,您并没有声明这样的类型;您避免了声明类型的需要(但牺牲了过程中的类型安全)。
  • 这行得通。而且我了解到我正在使用的编译器仅符合 C89。非常感谢!
【解决方案2】:

试试这个:

void (*(*f())())()

我总是发现cdecl 对此类任务有价值且有用。上面的查询是

declare f as function returning pointer to function returning pointer to function returning void

【讨论】:

  • +1 用于提及 cdecl。该工具对此类事情非常有帮助。
  • 您不能使用它来创建一个可以返回指向自身的指针的函数,这似乎是 OP 所追求的循环引用。
  • 谢谢,我不知道那个 cdecl。然而,尝试几个不同的例子似乎最终需要返回一个实际值。我正在寻找一种只返回指针的方法。
【解决方案3】:

这个呢?

typedef void (*rfp)(void);
typedef rfp (*fp)(void);

这不是完全循环的,但非常简单,对你来说可能没问题。

完整的解决方案可以在“Guru of the Week”找到完整的解释,是这样的:

 struct FuncPtr_;
 typedef FuncPtr_ (*FuncPtr)();
 struct FuncPtr_
 {
     FuncPtr_( FuncPtr pp ) : p( pp ) { }
     operator FuncPtr() { return p; }
     FuncPtr p;
 };


 FuncPtr_ f() { return f; } // natural return syntax
 int main()
 {
    FuncPtr p = f();  // natural usage syntax
    p();
 }

不是那么简单,但正确且便携...

【讨论】:

  • @caf:你说得对,我早就知道了。仍然,缺乏更好的解决方案......现在,请检查我在 GOTW 上找到的完整解决方案......
  • GOTW 的答案是 C++,绝对不是可移植的 C。
【解决方案4】:

我尝试了以下方法,确实避免了循环问题,因此在上下文中是错误的(并且需要强制转换);但是,如果您不需要真正循环或严格,它可以工作

#include <stdio.h>


typedef void *(*fp)(void);

fp funcB(void);

fp funcA(void)
{
  printf("funcA %p\n", funcB);
  return (fp)funcB;
}

fp funcB(void)
{
  printf("func B %p\n", funcA);
  return (fp)funcA;
}

int main()
{
  printf("%p %p\n", funcA, funcB);
  printf("%p %p\n", funcA(), funcB()); 
  return 0;
}

【讨论】:

  • 使用类型转换时会不自然~逻辑上它不是循环的,虽然它可以工作。
  • 除了不可移植性之外,您不能使用函数的返回值来调用,而不使用另一个强制转换。
  • 看caf的回答,喜欢的话可以拨打(*(((*((funkA()).fp))()).fp))();拨打funkA()...不要投进去。
  • 是的,您需要知道您拥有的指针是“fp”;虽然我发现它比其他解决方案更实用;如果我真的需要这样的东西,至少我会牺牲类型检查。可能不太好,但我希望不要太丢脸
  • @Stan:您不需要使用* 显式取消引用函数指针,因此您实际上可以直接使用funkA().fp().fp()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-29
  • 2011-09-09
相关资源
最近更新 更多