在C语言中,一个函数能否返回指向自身的指针?

3

背景

当你花几年时间写Haskell,然后回到裸机C代码时会发生什么:

问题

一个函数是否可以将其返回类型作为指向自身的指针?如果是这样,语法是什么?

函数名称在函数体内是否在作用域内?或者我可以获取当前正在执行的函数的地址吗?

例如:

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

为什么要这样做?

我有一个状态机处理用户输入的一些非常有限的控件,这意味着两个输入操作必须服务于多个不同的模式。我正在重构我的代码,使其更加易于维护,而不是充满switch语句和全局变量的混乱代码。如果我在Haskell中工作,我会调用当前模式函数与用户输入,并返回一个函数以便于随后的输入调用——无论是它自己还是新模式的处理程序。我开始尝试在C中实现这一点,但发现我不知道如何编写处理程序函数的类型。如果这行不通,我只需设置一个全局变量来存储下一个处理程序并继续生活,但我还是想问一下是否可以像在函数式语言中那样执行。

对于那些好奇的人,这一切都在ESP32上运行,这是一个更强大的处理器,但类似于Arduino所配备的处理器。


@CarlNorum 错了,这是完全没有问题的。 - 0___________
2
问题标题似乎与正文不匹配(标题听起来像是重复标记,但正文似乎在询问不同的事情)。 - R.. GitHub STOP HELPING ICE
1
你可以使用一个中间结构体来解决函数类型无法自我引用的问题(或类似的问题)。很遗憾他们关闭了你的问题,因为那个重复问题的答案看起来并不好。这里有一个例子(将其传递给 indent):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); }``` - user10678532
2
请重新修改您的问题标题,因为从问题正文中可以看出您并不想“返回”函数的地址。这样做的话,问题被重新开放的机会会更大。 - the busybee
1
无返回值的函数不会返回任何东西。 - wildplasser
显示剩余4条评论
3个回答

5

是的,在C语言中可以返回一个指向本身的函数指针

你需要寻找的返回类型是空指针 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;
}

输出:

该函数返回指向自身的指针。

该函数返回指向自身的指针。

编辑:

在阅读您问题的第二部分后,发现您可能需要递归回调。如果是这样,请在评论中澄清,我会相应地编辑我的答案。


不!任何奇怪的函数指针类型都可以,但 void* 可能不够大! - Deduplicator
@Deduplicator 如果是这种情况,你就必须处理警告“从不兼容的指针类型返回”和“从不兼容的指针类型初始化”。 - Ardent Coder

1
有没有可能一个函数的返回类型是指向该函数本身类型的指针?如果可以,语法是什么?
这是递归定义类型的要求,在C中至少不可能。返回指向函数本身的指针在this question中讨论过。
像其他人展示的那样,你需要一些技巧(void*struct)才能编译通过。标准兼容性没有被检查。
函数名在函数体内是可见的吗?
是的,当然。在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来实现这一点。

0

函数可以使用对自身的引用。这是完全没问题的。

#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 Haqverdili
@Ayxan 叫自己的名字也可以,没有区别。 - 0___________

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接