Программирование на C и C++

Онлайн справочник программиста на C и C++

Использование прототипов функции

Стандарт ANSI С расширяет концепцию предварительного описания функции. Данное расширенное описание называется прототипом функции.

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

тип имя_функции (список параметров);

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

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

Если возможно, С автоматически преобразует тип аргумента в тип, получаемый параметром. Тем не менее, некоторые преобразования типов недопустимы. Если функция имеет прототип, то все нелегальные преобразования будут найдены и появится сообщение об ошибке. В качестве примера, следующая программа вызывает сообщение об ошибке, поскольку пытается вызвать func() с указателем, а не с требуемым float. (Нельзя преобразовать указатель к типу float.)

/* Данная программа использует прототипы функций для достижения строгой проверки типов при вызове func(). Программа не компилируется из-за несоответствия между типом аргументов, определенных в прототипе функции, и типом аргументов, используемых при вызове функции. */

#include <stdio.h>
float func (int x, float у); /* прототип */
int main(void)
{
int x, *y;
x = 10;
у = &x;
func(x, у) ; /* несоответствие типов */
return 0;
}

float func (int x, float y)
{
printf("%f", у/(float)x);
return у/(float) x;
}

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

/* Программа не компилируется из-за несоответствия между числом параметров, определенных в прототипе функции, и числом аргументов, используемых при вызове функции. */

#include <stdio.h>
float func (int x, float у); /* прототип */
int main(void)
{
func (2, 2.0, 4); /* неверное число аргументов */
return 0;
}

float func {int x, float y)
{
printf ("%f", у/(float)x);
return у/(float) x;
}

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

char func (char *, int);

char func (char *str, int count);

Тем не менее, если включить имена параметров, компилятор использует имена для выдачи сообщений о несоответствии типов.

Некоторые функции типа printf() могут принимать переменное число аргументов. Переменное число аргументов определяется в прототипе с помощью многоточия. Например, прототип функции printf() выглядит так:

int printf(const char *fmt, ...);

Для создания функции с переменным числом аргументов надо обратиться к описанию стандартной библиотечной функции va_arg().

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