используя батут с одной функцией в качестве аргумента - PullRequest
0 голосов
/ 15 апреля 2020

Я знаю, что такое функция батута, но у меня были проблемы с предотвращением переполнения стека с помощью батутов. Пока что единственный способ, который я могу придумать, - это использовать глобальные переменные, которые не поощряют и могут усложнить программы.

Функция батута, которую я хочу использовать, показана ниже.

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

Пояснение: я не хочу модифицировать вышеприведенную функцию батута, но я хочу уменьшить создание стека.

1 Ответ

0 голосов
/ 15 апреля 2020

Сначала, вероятно, вы имеете в виду

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 просто возвращаете 0; ; -)

надежда звонки, которые вы можете делать

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

С вашим вторым определением после вашего редактирования компилятор не может оптимизировать, заменяя все на правильные return

На моем PI4 g cc 8.3.0 с опцией -O определяет окончательные рекурсии, и программа просто использует время для завершения sh, но без переполнения стека


Примечание g cc в качестве специального управления для батутного чехла, с выделенной опцией "-Wtrampoline"

...