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

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

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

<выражение>([<список выражений>])

<Выражение> вычисляется, и его результат интерпретируется как адрес функции. Выражение должно иметь тип функция.

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

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

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

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

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

<Выражение> должно ссылаться на функцию. Это означает, что функция может быть вызвана не только по идентификатору, но и через любое выражение, имеющее тип указателя на функцию.

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

Аналогичным образом функция вызывается через указатель. Предположим, что указатель на функцию объявлен следующим образом:

int (*fpointer)(int, int);

Идентификатор fpointer именует указатель на функцию с двумя аргументами типа int и возвращаемым значением типа int. Вызов функции в этом случае будет выглядеть так:

extern int f (int, int);

fpointer = &f; /*знак & необязателен */

(*fpointer)(3,4); /* можно и просто fpointer(3,4); */

Примеры:

/* пример 1 */

double *realcomp(double, double);

double a, b, *rp;

rp = realcomp(a, b);

/* пример 2 */

main()

{

long lift(int), slep(int), drop(int);

void work(int, long (*)(int));

int select, count;

.

.

.

switch(select) {

case 1: work(count, lift); break;

case 2: work(count, step); break;

case 3: work(count, drop); break;

default: break;

}

void work(int n, long (*func)(int))

{

int i;

long j;

for(i = j = 0; i < n; i++)

j += (*func)(i); /* можно просто j += func(i); */

}

В первом примере объявляется, а затем вызывается функция realcomp, Функции передаются два аргумента типа double. Возвращаемое значение—указатель на переменную типа double — присваивается rp.

Во втором примере функции work передаются два аргумента: целая переменная count и адрес функции (lift, step, или drop). Обратите внимание на то, что адрес функции может задаваться просто указанием идентификатора функции, поскольку идентификатор функции интерпретируется как адресное выражение. Чтобы использовать идентификатор функции подобным образом, функция должна быть объявлена или определена перед использованием идентификатора, иначе идентификатор не будет распознан. Поэтому в начале функции main приведены объявления функций lift, step, drop.

В начале функции main задано также предварительное объявление функции work. В этом объявлении тип второго формального параметра задан как указатель на функцию, принимающую один аргумент типа int и возвращающую значение типа long. Скобки, заключающие символ *, обязательны. Без них объявление специфицировало бы функцию, возвращающую указатель на значение типа long. Функция work вызывает выбранную функцию оператором

(*func) (i);

Аргумент i передается функции, вызываемой по указателю func.