【问题标题】:In C is it possible for a function to return a pointer to itself?在 C 中,函数是否可以返回指向自身的指针?
【发布时间】:2020-02-01 04:35:32
【问题描述】:

背景

这就是当你花几年时间编写 Haskell 然后回到裸机 C 代码时会发生的情况:

问题

函数是否可以将指针作为其返回类型,该指针与函数本身的类型相同?是这样,语法是什么?

函数的名称是否在函数体的范围内?或者我可以得到当前正在执行的函数的地址吗?

例如

void foo() {
  callmeback(&foo); // is this legal
}

您为什么要这样做?

我有一个状态机来处理来自一些非常有限的控件的用户输入,这意味着这两个输入操作必须服务于几种不同的模式。我正在将充满 switch 语句和全局变量的意大利面条代码重构为更易于维护的东西。如果我在 Haskell 中工作,我会使用用户输入调用当前模式函数,并让它返回一个函数以使用后续输入调用——它本身或新模式的处理程序。我开始在 C 中执行此操作,并意识到我不知道如何编写处理函数的类型。如果这不起作用,我将简单地为下一个处理程序设置一个全局变量并继续生活,但我只需要询问是否可以像在函数式语言中那样完成。

对于那些好奇的人,这一切都在 ESP32 上运行,这是一种功能更强大但类似于 Arduino 附带的处理器。

【问题讨论】:

  • 欺骗;不过,如果你真的下定决心,它确实有可能以特定于实现的方式破解它。
  • 问题标题似乎与正文不匹配(标题听起来像标记的重复,但正文似乎在问一些不同的问题)。
  • 您可以使用中间结构来解决函数缺乏类型自引用(或类似的东西;-))的问题。很遗憾他们关闭了你的 Q,因为对所谓的欺骗的答案看起来不太好。一个例子(传递给indent):#include <stdio.h> struct fun { struct fun (*fun)(int); }; struct fun fun(int x){ struct fun r = {fun}; printf("%d\n", x); return r; } int main(void){ fun(45).fun(32).fun(78); }
  • 请改写您问题的标题,因为您不想从问题的正文中返回函数的地址。那么问题很可能会被重新提出。
  • void 函数不返回任何内容。

标签: c function-pointers


【解决方案1】:

是的,可以在 C 中将 function pointer 返回给自身。

您要查找的返回类型是 void 指针 void*

是的,在 C 语言中,函数的名称在其主体中也是可见的。如果不是这样,递归之类的事情就不可能实现。

这里有一些代码用于说明:

#include <stdio.h>

void* demo() // See the usage of void pointer
{
    printf("This function returns a pointer to itself");
    return &demo;
    // return demo is also fine
    // don't return demo(), that would be recursion!
}

int main()
{
    // Syntax
    void (*demoPtr)() = demo();

    // Test if it worked
    demoPtr(); // There's no problem in ignoring the return value

    return 0;
}

输出:

这个函数返回一个指向自身的指针

这个函数返回一个指向自身的指针

编辑:

在阅读了您的问题的第二部分,其中提到了您对此的需求,我想您可能正在寻找recursioncallback。如果是这样,那么您可以在 cmets 中澄清它,我会相应地编辑我的答案。

【讨论】:

  • 不!任何奇怪的函数指针类型都可以,但void* 可能不够大!
  • @Deduplicator 在这种情况下,您必须处理警告从不兼容的指针类型返回从不兼容的指针类型初始化
【解决方案2】:

函数是否可以将指针作为其返回类型,该指针与函数本身的类型相同?是这样,语法是什么?

这是递归定义类型的必要条件,这是不可能的,至少在 C 中是不可能的。返回指向函数本身的指针在 this question 中讨论。

像其他人展示的那样,您需要一些技巧(void*structs)来编译它。那里没有检查标准合规性。

函数名是否在函数体的范围内?

是的,当然。递归在 C 中很好。

[…]我能得到当前正在执行的函数的地址吗?

只是函数的名称。这是您的场景示例:

#include <stdio.h>

static void caller(void (*callee)(int)) {
  printf("Begin of %s(...)\n", __func__);
  callee(23);
  printf("End of %s(...)\n", __func__);
}

static void to_be_called(int param) {
  printf("Begin of %s(%d)\n", __func__, param);
  if (param == 0) {
    caller(&to_be_called);
  }
  printf("End of %s(%d)\n", __func__, param);
}

int main(void) {
  to_be_called(0);
  return 0;
}

您的计划在嵌入式 C 中并不新鲜:通过设置指向当前状态函数的指针来实现状态机。但是您将设置下一个指针不是通过返回它,而是通过调用一个setter函数。一些开发人员甚至为此使用全局变量,brr

【讨论】:

    【解决方案3】:

    函数可以使用对自身的引用。 100% 没问题。

    #include <stdlib.h>
    #include <stdio.h>
    
    volatile int x;
    
    void foo(void (*fptr)())
    {
        printf("Iteration: %d Function:%s\n", x++, __FUNCTION__);
        if(x < 10) fptr(foo);
    }
    
    void bar(void (*fptr)())
    {
        printf("Iteration: %d Function:%s\n", x++, __FUNCTION__);
        if(x < 10) fptr(bar);
    }
    
    
    int main()
    {
        bar(foo);
    }
    

    【讨论】:

    • 很高兴引用标准的相关部分。
    • @Ayxan 和自己打电话一样。没有区别
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-29
    • 2012-02-02
    • 2013-04-10
    相关资源
    最近更新 更多