Примеры:
/* пример 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.
Фактический аргумент может быть любым значением базового типа, структурой, объединением или указателем. Все фактические аргументы передаются по значению. Массивы и функции не могут быть переданы как параметры, могут передаваться указатели на эти объекты. Поэтому массивы и функции передаются по ссылке. Значения фактических аргументов копируются в соответствующие формальные параметры. Функция использует только эти копии, не изменяя сами переменные, с которых копия была сделана.
Возможность доступа из функции не к копиям значений, а к самим переменным обеспечивают указатели. Указатель на переменную содержит ее адрес, и функция может использовать этот адрес для изменения значения переменной.
Фактические аргументы (выражения в вызове функции) вычисляются и преобразуются следующим образом:
1) Если имеется объявление со списком типов аргументов (прототип), то при вызове функции выполняются преобразования по умолчанию над типом каждого фактического аргумента, заданным в списке типов аргументов. Затем фактический аргумент приводится к полученному преобразованному типу. Независимо от аргумента, тип соответствующего формального параметра в списке параметров функции также подвергается преобразованиям по умолчанию. Затем полученный тип фактического аргумента сравнивается с типом соответствующего формального параметра. В случае несоответствия никакого преобразования не производится, но компилятор выдает такое же предупреждающее сообщение, как для выражения присваивания, когда типы левого и правого операнда не совпадают.
2) Если объявление со списком типов аргументов (прототип) отсутствует, то преобразования по умолчанию производятся отдельно для каждого аргумента, не имеющего соответствующего имени типа. Если список типов аргументов завершен многоточием и задано больше фактических аргументов, чем имен типов в списке, то лишние фактические аргументы подвергаются только преобразованиям по умолчанию. Соответствующий формальный параметр в списке параметров функции также подвергается преобразованиям по умолчанию.
Если список типов аргументов не завершен многоточием, а передается больше фактических аргументов, чем объявлено имен в списке, то компилятор выдаст предупреждающее сообщение в СП MSC и сообщение об ошибке в СП ТС.
Если список типов аргументов содержит специальное имя типа void, то компилятор языка Си ожидает отсутствие фактических аргументов в вызове функции и отсутствие формальных параметров в определении функции. Если какое-либо из этих условий окажется нарушено, то компилятор языка Си выдает предупреждающее сообщение в СП MSC и сообщение об ошибке в СП ТС.
Если в списке типов аргументов используются модификаторы near, far, huge, то компилятор языка Си может также выполнить неявно преобразования аргументов-указателей к соответствующему формату (см. раздел 4.7.3 "Преобразования типов при вызовах функций").