Рекурсивная функция может быть встроена?

«Является ли класс для одной из ваших форм формой (например, переименованной из Формы1 в Форму)? Если это так, вам следует переименовать ее». @madreflection

Работало переименование формы из «Формы» в другое имя.

132
задан Cody Brocious 10 October 2008 в 05:34
поделиться

9 ответов

Во-первых, inline спецификация на функции является просто подсказкой. Компилятор может (и часто делает), полностью игнорируют присутствие или отсутствие inline спецификатор. После этих слов компилятор может встраивать рекурсивную функцию, хотя он может развернуть бесконечный цикл. Это просто должно установить границу на уровне, к которому это "развернет" функцию.

оптимизирующий компилятор мог бы повернуть этот код:

inline int factorial(int n)
{
    if (n <= 1)
    {
        return 1;
    }
    else
    {
        return n * factorial(n - 1);
    }
}

int f(int x)
{
    return factorial(x);
}

в этот код:

int factorial(int n)
{
    if (n <= 1)
    {
        return 1;
    }
    else
    {
        return n * factorial(n - 1);
    }
}

int f(int x)
{
    if (x <= 1)
    {
        return 1;
    }
    else
    {
        int x2 = x - 1;
        if (x2 <= 1)
        {
            return x * 1;
        }
        else
        {
            int x3 = x2 - 1;
            if (x3 <= 1)
            {
                return x * x2 * 1;
            }
            else
            {
                return x * x2 * x3 * factorial(x3 - 1);
            }
        }
    }
}

В этом случае, мы в основном встроили функцию 3 раза. Некоторые компиляторы делают , выполняют эту оптимизацию. Я вспоминаю MSVC ++ наличие установки настраивать уровень встраивания, которое было бы выполнено на рекурсивных функциях (до 20, я верю).

134
ответ дан 24 November 2019 в 00:12
поделиться

Компилятор создает граф вызовов; когда цикл обнаруживается, называя себя, функция больше не встраивается после определенной глубины (n=1, 10, 100, независимо от того, что компилятор настраивается на).

6
ответ дан 24 November 2019 в 00:12
поделиться

AFAIK GCC сделает устранение последнего вызова на рекурсивных функциях, если это возможно. Ваша функция однако не является рекурсивным хвостом.

7
ответ дан 24 November 2019 в 00:12
поделиться

Действительно, если Ваш компилятор не действует разумно, он может попытаться вставить копии Вашего inline функция d рекурсивно, создав бесконечно большой код. Большинство современных компиляторов распознает это, как бы то ни было. Они могут также:

  1. Не встраивают функцию во всем
  2. Встроенный это до определенной глубины, и если это не завершилось к тому времени, назовите отдельный экземпляр своей функции с помощью соглашения о вызовах стандартной функции. Это может заботиться о многих общих падежах высокоэффективным способом при оставлении нейтрализации для редкого случая с большой глубиной вызова. Это также означает, что Вы сохраняете и встроенные и отдельные версии кода той функции вокруг.

Для случая 2, много компиляторов имеют #pragma с, которую можно установить для определения максимальной глубины, на которую это должно быть сделано. В gcc, можно также передать это в от командной строки с --max-inline-insns-recursive (см. больше информации здесь ).

23
ответ дан 24 November 2019 в 00:12
поделиться

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

3
ответ дан 24 November 2019 в 00:12
поделиться

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

, Но главным образом этим управляют встроенное ключевое слово и переключатели компилятора (Например, у Вас может быть он автоматические встроенные небольшие функции даже без ключевого слова.) Его важное, чтобы отметить, что компиляции Отладки никогда не должны встраивать, поскольку стек вызовов не будет сохранен для зеркального отражения вызовов, которые Вы создали в коде.

1
ответ дан 24 November 2019 в 00:12
поделиться

См. ответы, уже данные для того, почему это не будет обычно работать.

Как "сноска", Вы могли достигнуть эффекта, который Вы ищете (по крайней мере, для факториала, который Вы используете в качестве примера), использование шаблонное метапрограммирование . Вставка из Википедии:

template <int N>
struct Factorial 
{
    enum { value = N * Factorial<N - 1>::value };
};

template <>
struct Factorial<0> 
{
    enum { value = 1 };
};
2
ответ дан 24 November 2019 в 00:12
поделиться

"Как компилятор решает, встроить ли функцию или нет?"

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

, исходный код программы все еще должен соблюсти правила для встроенных функций. Встраивается ли функция, необходимо подготовиться к возможности, что она будет встроена (некоторое неизвестное количество раз).

оператор Wikipedia, что рекурсивные макросы являются обычно недопустимыми взглядами, скорее плохо информированными. C и C++ предотвращают рекурсивные вызовы, но единица перевода не становится недопустимой, содержа макро-код, который похож на него, было бы рекурсивным. В ассемблерах рекурсивные макросы обычно законны.

1
ответ дан 24 November 2019 в 00:12
поделиться

Некоторые компиляторы (Т.е. Borland C++) не встраивают код, который содержит условные операторы (если, случай, в то время как и т.д.), таким образом, рекурсивная функция в Вашем примере не была бы встроена.

0
ответ дан 24 November 2019 в 00:12
поделиться