Можно ли заставить оптимизацию хвостового вызова на GCC / Clang?

Я пытаюсь написать программу в функциональном стиле С C как можно больше. Я знаю прекрасные компиляторы, такие как GCC / Clang, делают оптимизацию хвостового вызова молча, но это не гарантировано. Есть ли возможность принудительной оптимизации хвостового вызова на компиляторах? (Конечно, когда только он называется в конце себя)

4 ответов


Clang не делает никаких оптимизаций вообще. Существует LLVM pass tailcallelim Что может делать то, что вы хотите (но это не гарантируется). Вы можете запустить его отдельно с помощью opt.


мета ответ:

есть несколько уроков, которые полезно взять на себя в C из функциональных языков: используйте небольшие функции, используйте функции, которые не мутируют ни глобалы, ни входные аргументы, не бойтесь указателей функций. Но есть предел тому, что вы можете разумно сделать здесь, и полагаясь на устранение хвостового вызова ('tail-call оптимизация ' на самом деле не правильный термин), вероятно, выходит за рамки того, что полезно. Вы не можете заставить компилятор использовать этот стратегия, и даже если бы вы могли, получившаяся буква " С "была бы чрезвычайно однообразной и трудно читаемой для других, включая ваше будущее "я".

используйте языки для своих сильных сторон. C is хороши для некоторых вещей, поэтому используйте его для тех, в хорошем стиле C. Если вы хотите разные сильные стороны ,или если вы хотите использовать функциональный стиль (отличное решение!), используйте функциональный язык.


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


Если это действительно хвостовой вызов, то цикл while или goto не будут сильно отличаться от рекурсивного вызова. Просто обновите все переменные вместо того, чтобы передавать их в качестве параметров. AFAIK это единственный кросс-платформенный способ в C контролировать использование стека на всех уровнях оптимизации. Он также может быть более читаемым, поскольку у вас есть одна функция с инициализацией, за которой следует цикл, который довольно идиоматичен. Для хвостовой рекурсивной версии требуются две функции: одна для инициализации и одна для рекурсивной части.