【问题标题】:using a trampoline with one function as an argument使用带有一个函数作为参数的蹦床
【发布时间】:2020-04-15 15:16:58
【问题描述】:

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

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

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

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

【问题讨论】:

  • 可能你的意思是 if (*n == 0) if f1
  • @bruno 感谢您发现错字
  • 严格来说,C不保证void *可以保存一个函数指针,只能保存一个数据指针。
  • 但是@TomKarzes 参数语法指定蹦床必须接受一个空函数指针,对吧?
  • @gt453 void 函数指针与 void 指针不同。实际上,您几乎可以肯定是安全的,但严格来说,函数指针的大小可能与数据指针不同。有关详细信息,请参阅this link

标签: c pointers trampolines


【解决方案1】:

首先你的意思可能是

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 8.3.0 上使用 -O 选项检测最终递归,程序只使用时间来完成,但没有堆栈溢出


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

【讨论】:

  • @gt453 我认为这是一个错误的问题,因为长期以来所有编译器都检测到最终递归,您是否使用梁龙编译 8080 ?
  • @gt453 我在 PI4 (raspbian) 上运行,而您的新版本需要时间才能完成
  • 是的,但是你能找到一个和我的新版本一样工作但不使用全局变量的版本吗?全局变量可以在程序的不同部分创建隐藏的依赖关系,但只要我进行正确的函数调用,它们仍然是可管理的。有什么方法可以避免使用不涉及使用全局变量的给定蹦床函数创建堆栈帧?
  • @gt453 请停止删除你的问题,每次我的答案版本丢失,我都必须重做,这很紧张
  • 好的,但我仍然不知道如何解决我的实际问题。
猜你喜欢
  • 2011-12-27
  • 2021-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多