使用带有一个函数的蹦床作为参数

using a trampoline with one function as an argument

我知道蹦床函数是什么,但我一直无法使用蹦床来避免堆栈溢出。到目前为止,我能想到的唯一方法是使用全局变量,不鼓励使用全局变量,并且会使程序复杂化。

我要使用的蹦床功能如下图

void trampoline(void *(*fun)()) {
  while (fun != NULL) {
    void *callback = fun();
    fun = (void *(*)())callback;
  }
}

当我尝试传入带参数的函数时,例如下面代码片段中的那些,我最终创建了堆栈,这不是我想要的。我想知道是否有一种方法可以在不使用全局变量或传入任何额外参数的情况下使用我的蹦床函数?

void *f1();
void *f2();

void *f1(int *n) {
  if (*n == 0) {
    return NULL;
  } else {
    return f2(n);
  }
}

void *f2(int *n) {
  --*n;
  return f1(n);
}

int main() {
  int a = 1000000;
  trampoline(f1(&a));
  return 0;
}

下面的程序按照我想要的方式运行,但它使用了一个全局变量,这是普遍不鼓励的。

#include <stdio.h>
int a = 1000;

void trampoline(void *(*f)()) {
  while (f) {
    void *g = f();
    f = (void *(*)())g;
  }
}

void *f1();
void *f2();

void *f1() {
  if (a == 0) {
    return NULL;
  } else {
    return f2;
  }
}

void *f2() {
  --a;
  return f1;
}

int main() {

  trampoline(f1);
  return 0;
}

Clarification: I do not want to modify the trampoline function above, but I want reduced stack creation.

首先你的意思可能是

void *f1(int *n) {
  if (*n == 0) {  /* <<< */
    return NULL;
  } else {
    return f2(n);
  }
}

而不是

void *f1(int *n) {
  if (n == 0) {
    return NULL;
  } else {
    return f2(n);
  }
}

通过优化编译,编译器将检测两个函数中的最终递归,并且使用的堆栈大小将保持不变,并且不会与 a 链接。

事实上,对于编译器,你 main 只是 return 0; ;-)

希望你能做的电话

int main(int argc, char ** argv) {
  int a = argc * 1000000;
  trampoline(f1(&a));
  return a;
}

使用您编辑后的第二个定义,编译器无法优化全部替换为正确 return

在我的 PI4 gcc 带有选项 -O 的 8.3.0 检测到最终递归,程序只使用时间完成,但没有堆栈溢出


注意 gcc 作为 trampoline 案例的特殊管理,带有专用选项“-Wtrampoline”