0

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

我想使用的蹦床功能如下图所示。

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;
}

澄清:我不想修改上面的蹦床功能,但我想减少堆栈创建。

4

1 回答 1

0

首先可能你的意思是

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);
  }
}

使用优化进行编译,编译器将检测两个函数中的最终递归,并且使用的堆栈大小将是恒定的,并且不与.

事实上,对于编译器来说,你的main只是返回 0;;-)

希望你能做的电话

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

在您编辑后的第二个定义中,编译器无法优化全部替换为正确的返回

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


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

于 2020-04-15T15:27:31.413 回答