Skip to main content

Что такое вызов в хвост?

В компьютерном программировании хвостовой вызов - это особая ситуация в исходном коде программы, в которой функция, подпрограмма или процедура возвращает ожидаемое значение, вызывая другую функцию вместо простой передачи переменной, содержащей возвращаемое значение. Само имя обозначает, что функция, вызываемая для вычисления возвращаемого значения, находится в конце или в конце функции, вызывающей ее для предоставления возвращаемого значения. Конечный вызов представляет интерес для некоторых программистов, потому что при определенных оптимизациях или поведении компилятора дополнительное пространство стека не используется для хранения местоположений кода основной функции; вместо этого функция хвоста используется для генерации отчетов о возвращаемых значениях непосредственно обратно в точку вызова, где была вызвана исходная функция. Использование хвостового вызова особенно полезно в ситуациях, в которых используется рекурсия, поскольку объем стекового пространства, используемого для хранения адресов вызывающих, в случаях, когда рекурсивные вызовы вкладываются очень глубоко, могут быстро закончиться и остановить выполнение программы. Хотя использование хвостовых вызовов может помочь увеличить скорость, использование памяти и эффективность в программе, это также может привести к ситуациям, когда исходный код реструктурируется для использования вызовов таким образом, что затрудняет отладку и отслеживание, особенно в случаях рекурсии.

Существование оконечного вызова во многом связано с тем, как стек вызовов работает в большинстве компьютерных программ и системных архитектур. Стек, который подобен стеку пластин, является структурой данных «первым пришел - последним вышел». Когда вызывается функция, подпрограмма или процедура, адрес, с которого выполняется вызов, называемый кадром стека, сохраняется в стеке. Это означает, что программа, которая вызывает функцию A, которая затем вызывает функцию B, будет иметь два стековых фрейма, один для функции B, а другой под ней для функции A. После завершения выполнения функции B ее стековый кадр извлекается из верхней части stack и выполнение возвращаются к функции A, у которой после завершения работы кадр сбрасывается со стека, и, наконец, возвращается программный элемент управления в точку, из которой первоначально была вызвана первая функция.

Когда используется хвостовой вызов, оператор return в функции напрямую использует возвращаемое значение другой функции в качестве данных, которые будут отправлены в вызывающий код. В приведенном выше примере, если функция A вызывает функцию B напрямую с оператором return, то был сформирован хвостовой вызов. Внутри стека вызовов вместо наличия стекового фрейма для функций A и B функция B получит адрес возврата от функции A, а фрейм стека функции A будет извлечен и удален, то есть функция B передаст возвращаемое значение непосредственно обратно. в местоположение, которое вызвало функцию A, без необходимости сначала передавать управление обратно функции A. Это увеличивает скорость вызовов функций, а также помогает уменьшить объем информации в стеке.

Свойства хвостового вызова могут сделать их очень привлекательным вариантом для рекурсивных функций. Рекурсивная функция - это функция, которая вызывает себя несколько раз для вычисления значения, как это может быть в случае обхода структуры данных списка. Для вызовов вложенных функций не создаются дополнительные кадры стека, поэтому очень глубокие уровни рекурсии могут быть безопасно выполнены без непосредственной угрозы переполнения стека и возможного завершения программы.