Вызов функции

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

Чуть позже мы рассмотрим тип "указатель на функцию", который позволяет создавать переменные, указывающие на функцию с конкретными характеристиками, и затем вызывать её не по имени, а посредством этой переменной.

Продолжая пример с функцией Fibo, осуществим её вызов из функции OnStart. Для этого заведем переменную f для хранения результирующего числа и в выражении её инициализации укажем имя функции Fibo и целое число (например, 10) в качестве аргумента, в круглых скобках.

void OnStart()
{
   int f = Fibo(10); 
   Print(f); // 89
}

Напомним, что мы не обязаны заводить переменную для приема значения из функции. Вместо этого можно вызывать функцию непосредственно из выражения, например, "2*Fibo(10)" или "Print(Fibo(10))". Тогда её значение подставится в выражение на место вызова. Здесь вспомогательная переменная f заведена, чтобы выделить в отдельной инструкции вызов и возврат значения.

Процесс вызова включает следующие этапы:

  • выполнение последовательности инструкций вызывающей функции (OnStart) приостанавливается;
  • значение аргумента попадает во входной параметр n вызываемой функции (Fibo);
  • начинают выполняться её инструкции;
  • когда она полностью отработает, то передает результат обратно (вспоминаем инструкцию return внутри);
  • результат попадет в переменную f;
  • после этого продолжится выполнение функции OnStart, то есть вывод числа в журнал (Print).

Для каждого вызова функции компилятор генерирует вспомогательный двоичный код (программисту о нём заботиться не надо). Суть этого кода в том, что перед вызовом функции он заносит в стек текущую позицию в программе, а после завершения вызова извлекает её и использует для возврата к инструкциям, следующим за вызовом функции. Когда одна функция вызывает другую, та вызывает еще одну, вторая вызывает третью и так далее, на стеке стопкой накапливаются обратные адреса переходов по всей иерархии вызванных функций (отсюда и название — стек). По мере отработки вложенных вызовов функций, стек будет в обратном порядке очищаться. Напомним, что на стеке также выделяется память для локальных переменных каждой функции.