Допустим, что в некотором месте в вашем коде происходит вызов определенной функции. Зададимся вопросом, при каких условиях при компилировании этого участка кода компилятор не выдаст ошибки. На этот вопрос существует простой ответ. Где-то в том же файле, в котором осуществляется вызов функции, перед операцией, в которой осуществляется вызов, должны присутствовать прототип или описание функции. Кроме того, аргументы и тип возвращаемого значения в вызове должны соответствовать аргументам и типу возвращаемого значения в прототипе и в описании функции.
Итак, что же такое прототип функции? Прототип имеет следующий вид.
// прототип функции void function(int arg1, double arg2); // в конце определения всегда ставится точка с запятой
Как видно в прототипе указываются по порядку тип возвращаемого значения (в данном примере void
), название функции (в данном случае function
) и список параметров в скобках. Объявление прототипа должно заканчиваться точкой с запятой.
Для чего нужен прототип функции? Прототип и описание функции используются компилятором для того, чтобы вызов функции происходил правильным образом. Для этого компилятор сначала смотрит имя вызываемой функции и ищет в файле прототип или описание этой функции. Если найден прототип или описание, то проверяются аргументы, передаваемые функции в вызове, и использование возвращаемого значения.
Для чего нужен именно прототип? Почему нельзя ограничиться использованием одного описания функции? Прототип стал необходим после того, как стандарты языка С изменились таким образом, что перед вызовом функции в файле необходимо каким либо образом ее описать. Проблема состоит в том, что имя функции имеет глобальную область видимости (если ее описание находится вне всяких локальных областей). Допустим, что описание функции находится в отдельном исходном файле. Также допустим, что необходимо осуществить вызов этой же функции в нескольких других исходных файлах. Если нет прототипа, то в каждый такой исходный файл необходимо включить полное описание функции. Компилятор будет интерпретировать это как переопределение. Если же мы используем прототип, то мы можем включать этот прототип в столько исходных файлов, сколько нам необходимо.
Как лучше всего использовать прототип функции. Лучше всего описание функции включить в отдельный исходный файл. После этого надо скомпилировать этот файл и получить объектный файл. Прототип следует помесить в заголовочный файл и включать его директивой #include
в те исходные файлы, в которых присутствует вызов функции.