g cc поведение при компиляции c рекурсивной функции с параметрами const - PullRequest
1 голос
/ 24 февраля 2020

Учитывая следующую функцию:

void rec_func(int a, int b, const int c) {
    /*
        flow control and stuff here
    */
    rec_func(a - 1, b, c);
}

Будет ли g cc понимать, что c - это то же самое постоянное значение для всех рекурсивных вызовов, а затем будет использовать одну и ту же переменную для всех вызовов, или он будет копировать значение c в новую переменную c каждый вызов?

Тот же вопрос для b, даже если он не помечен как const, поймет ли g cc, что это неявно const?

Edit1:
Вопрос сделан с точки зрения оптимизации

Edit2:
Под "неявным const" я не имею в виду какое-то ключевое слово. Я имею в виду переменную, не помеченную модификатором const, значение которой никогда не изменится после инициализации.

Ответы [ 2 ]

3 голосов
/ 24 февраля 2020

My думаю, означает, что вы подходите к этому с точки зрения оптимизации.

Если это так:

  1. Не беспокойтесь об этом ; компилятор намного умнее вас * и сработает хорошо.
  2. Рекурсия редко бывает "оптимальной" по производительности.

Если вы не пытаетесь изменить b или c в вашей управляющей логике c, компилятор может сделать что-то умное, но передача int вряд ли будет большой проблемой. Если вы проходите вокруг гигантской структуры, вы можете вместо этого использовать указатель или ссылку.

В любом случае, вы можете видеть, что G CC собирается делать с удивительным инструментом godbolt .

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

[*] Не вы конкретно!

2 голосов
/ 26 февраля 2020

Будет ли g cc понимать, что c является одним и тем же постоянным значением для всех рекурсивных вызовов, а затем будет использовать одну и ту же переменную для всех вызовов, или он скопирует значение c в new c переменная каждый вызов?

В этом конкретном случае g cc видит, что значения никогда не используются разумным способом. На x64 gcc -Os -S file.c генерирует следующий код сборки (file.s, для краткости вырезаны нерелевантные детали):

rec_func:
.L2:
    jmp .L2

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

int rec_func (int a, int b, const int c)
{
    return a == b
        ? c + a
        : 1 - rec_func (a - c, b, c);
}

, снова скомпилированные с -Os (компиляция для скорости также не будет использовать рекурсию, конечно)

rec_func:
    movl    $1, %ecx
    xorl    %eax, %eax
.L3:
    cmpl    %esi, %edi
    je  .L5
    addl    %ecx, %eax
    subl    %edx, %edi
    negl    %ecx
    jmp .L3
.L5:
    addl    %edx, %edi
    imull   %ecx, %edi
    addl    %edi, %eax
    ret

Нет вызова / перейти к rec_func в любом месте. Даже с c + 1 в качестве третьего аргумента сгенерированный код будет только на одну инструкцию длиннее.

поймет ли g cc, что это неявно const?

Да. Что касается const в const c, это ничего не меняет; любой реальный компилятор, подходящий для практических целей, сам определит, что c никогда не изменится. Текущий случай const является для вас только напоминанием о том, что c доступен только для чтения, и вы не измените его.

...