Что называется прототипом функции
Перейти к содержимому

Что называется прототипом функции

  • автор:

Прототип функции

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

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

Пример

В качестве примера, рассмотрим следующий прототип функции:

int foo(int n); 

Этот прототип объявляет функцию с именем «foo», которая принимает один аргумент «n» целого типа и возвращает целое число. Определение функции может располагаться где угодно в программе, но определение требуется только в случае её использования.

Использование

Уведомление компилятора

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

#include /* * При реализации этого прототипа компилятор выдаст сообщение об ошибке * в main(). Если он будет пропущен, то и сообщения об ошибке не будет. */ int foo(int n); /* Прототип функции */ int main(void) /* Вызов функции */  printf("%d\n", foo()); /* ОШИБКА: у foo отсутствует аргумент! */ return 0; > int foo(int n) /* Вызываемая функция */  if (n == 0) return 1; else return n * foo(n - 1); > 

Функция «foo» ожидает аргумент целого типа, находящийся в стеке при вызове. Если прототип пропущен, компилятор не может это обработать и «foo» завершит операцию на некоторых других данных стека (вероятно, это будет обратный адрес или значение переменной, не входящей в область допустимых значений). Включением прототипа функции вы информируете компилятор о том, что функция «foo» принимает один аргумент целого типа и вы тем самым позволяете компилятору обрабатывать подобные виды ошибок.

Создание библиотечных интерфейсов

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

Объявления класса

В C++ прототипы функций также используются в определении классов.

Ссылки

  • Kernighan, Brian W. & Ritchie, Dennis M. (1988), «The C Programming Language» (2nd ed.), Upper Saddle River, NJ: Prentice Hall PTR, ISBN 0131103628

См. также

  • Сигнатура типа
  • Язык программирования Си

6. Прототипы функций.

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

В общем виде прототип функции должен выглядеть таким образом:

тип имя_функции(тип имя_парам1, тип имя_парам2, . имя_парамN);

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

Хотя прототипы формально не требуются, но их использование очень желательно. (Впрочем, в C++ прототипы обязательны!)

7. Перегрузка функций

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

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

В сигнатуру функции входят:

  • порядок и типы параметров
  • модификатор const для нестатических функций

Возвращаемое значение не входит в сигнатуру.

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

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

8. Значения формальных параметров по умолчанию.

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

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

Прототипы функций

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

Синтаксис

declaration :
declaration-specifiers attribute-seq opt init-declarator-list opt ;

/* attribute-seq необ. относится только к продуктам Майкрософт */

declaration-specifiers :
storage-class-specifier declaration-specifiers необ.
type-specifier declaration-specifiers необ.
type-qualifier declaration-specifiers необ.

init-declarator-list :
init-declarator
init-declarator-list , init-declarator

init-declarator :
declarator
declarator = initializer

direct-declarator : /* Оператор объявления функции */
direct-declarator ( parameter-type-list ) /* Оператор объявления нового стиля */
direct-declarator ( identifier-list opt ) /* Оператор объявления старого стиля */

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

Ниже перечислены важные случаи применения прототипов функций:

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

Преобразованный тип каждого параметра определяет интерпретацию аргументов, помещаемых в стек при вызове функции. Несоответствие типов аргументов и параметров может приводить к неправильной интерпретации аргументов в стеке. Например, если на 16-разрядном компьютере в качестве аргумента передается 16-разрядный указатель, объявленный как параметр long , первые 32 бита в стеке интерпретируются как параметр типа long . Эта ошибка создает проблемы не только с параметром long , но и со всеми последующими параметрами. Ошибки такого типа можно обнаруживать, объявляя полные прототипы для всех функций.

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

Полные объявления параметров ( int a ) могут использоваться совместно с абстрактными деклараторами ( int ) в одном объявлении. Например, следующее объявление является допустимым:

int add( int a, int ); 

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

Теперь область прототипа в компиляторе Microsoft C соответствует стандарту ANSI при компиляции с параметром /Za . Если вы объявите в прототипе тег struct или union , этот тег добавляется именно в этой области, а не в глобальной области. Например, если выполнять компиляцию с параметром /Za в соответствии со стандартом ANSI, эту функцию невозможно будет вызвать без получения ошибки несоответствия типов:

void func1( struct S * ); 

Чтобы исправить код, определите или объявите struct или union в глобальной области перед прототипом функции:

struct S; void func1( struct S * ); 

В /Ze разделе тег по-прежнему вводится на глобальном область.

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

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

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

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

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

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

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

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

#include
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
float func (int x, float у); /* прототип */
int main(void)
func (2, 2.0, 4); /* неверное число аргументов */
return 0;
>

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

char func (char *, int);

char func (char *str, int count);

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

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

int printf(const char *fmt, . );

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

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

  • Прототипы стандартных библиотечных функций
  • Создание прототипов функций, не имеющих параметров

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *