Подтвердить что ты не робот

Рекурсия без рекурсивного вызова?

Нашел это on/prog/. Я на самом деле GDB'd, и да, это была настоящая рекурсия. Но как это произошло?

// This works on 32-bit x86 Linux with gcc as long as you don't enable optimization.

#include <stdio.h>
#include <stdlib.h>

static void factorial(int in, int *out)
{
  *(&in-1)-=5-5*(1/in);
  *out*=in--;
}

int main(int argc, char **argv) 
{
  int result=1;
  int number=0;

  if (argc!=2) 
    exit(1);

  number=atoi(argv[1]);
  if (number<1)
    exit(2);

  factorial(number, &result);
  printf("%d! = %d\n", number, result);
  return 0;
}


$ ./factorial 3
3! = 6

$ ./factorial 5
5! = 120
4b9b3361

Ответ 1

Сладкое.;)

Это крайне не переносимый код, который работает только на x86. Что он делает, это изменение адреса возврата в стеке, так что если in>1, функция возвращает не инструкцию, следуя инструкции call, а самой команде вызова. Команда вызова на x86 - это пять байтов (один код операции плюс 4-байтовый адрес назначения вызова), поэтому пять нужно вычесть из адреса возврата.

Это

*(&in-1)-=5-5*(1/in);

- просто запутанный способ сказать

if(in>1)
    *(&in-1)-=5;

И &in-1 - это то, где обратный адрес живет в стеке.

Ответ 2

Это искажает обратные адреса в стеке, чтобы вызвать рекурсию.

*(&in-1)-=5-5*(1/in);

&in-1 - это, вероятно, перенаправленный адрес возврата. остальное - просто неприятная магия.

Ответ 3

Как сказано выше * (& in-1) является обратным адресом , 5 (я думаю) - это размер функции (в словах?), и он вычитает как для получения адреса, где начинается функция.забастовкa >

EDIT: Поскольку я думаю, что изменение адреса возврата является постоянным, я не понимаю, почему 5 вычитается, когда в > 1;

EDIT2: см. комментарии

Команда возврата ассемблера переходит только к адресу, расположенному в верхней части стека.

Из-за соглашения о вызове параметры вставляются в стек и удаляются из него вызывающим. Поскольку существует только один реальный вызов, рекурсия отсутствует, параметры и обратный адрес (указатель) разделяются между итерациями.

Это больше похоже на цикл, чем на рекурсивную функцию.