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

       

A. Определение функции


Определение функции имеет следующий вид:

определение-функции: спецификаторы-объявлениянеоб объявитель список-объявленийнеоб

составная-инструкция

Из спецификаторов класса памяти в спецификаторах-объявлениях возможны только extern и static; различия между последними рассматриваются в A11.2.

Типом возвращаемого функцией значения может быть арифметический тип, структура, объединение, указатель и void, но не "функция" и не "массив". Объявитель в объявлении функции должен явно указывать на то, что описываемый им идентификатор имеет тип "функция", т. е. он должен иметь одну из следующих двух форм (A8.6.3):

собственно-объявитель ( список-типов-параметров ) собственно-объявитель ( список-идентификаторовнеоб)

где собственно-объявитель есть идентификатор или идентификатор, заключенный в скобки. Заметим, что тип "функция" посредством typedef получить нельзя.

Первая форма соответствует определению функции новым способом, для которого характерно объявление параметров в списке-типов-параметров вместе с их типами; за объявителем не должно быть списка-объявлений. Если список-типов-параметров не состоит из одного-единственного слова void, показывающего, что параметров у функции нет, то в каждом объявителе в списке-типов-параметров обязан присутствовать идентификатор. Если список-типов-параметров заканчивается знаками ", ...", то вызов функции может иметь аргументов больше, чем параметров; в таком случае, чтобы обращаться к дополнительным аргументам, следует пользоваться механизмом макроса va_arg из заголовочного файла <stdarg.h>, описанного в приложении B. Функции с переменным числом аргументов должны иметь по крайней мере один именованный параметр.

Вторая форма - определение функции старым способом. Список-идентификаторов содержит имена параметров, а список-объявлений приписывает им типы. В списке- объявлении разрешено объявлять только именованные параметры, инициализация запрещается, и из спецификаторов класса памяти возможен только register.


И в том и другом способе определения функции мыслится, что все параметры как бы объявлены в самом начале составной инструкции, образующей тело функции, и совпадающие с ними имена здесь объявляться не должны (хотя, как и любые идентификаторы, их можно переобъявить в более внутренних блоках). Объявление параметра "массив из типа" можно трактовать как "указатель на тип", аналогично объявлению параметра объявление "функция, возвращающая тип" можно трактовать как "указатель на функцию, возвращающую тип". В момент вызова функции ее аргументы соответствующим образом преобразуются и присваиваются параметрам (см. A7.3.2).

Новый способ определения функций введен ANSI-стандартом. Есть также небольшие изменения в операции повышения типа; в первой версии языка параметры типа float следовало читать как double. Различие между float и double становилось заметным, лишь когда внутри функции генерировался указатель на параметр.

Ниже приведен пример определения функции новым способом:

int max(int a, int b, int c) { int m;

m = (a > b) ? a: b; return (m > с) ? m : с; }

Здесь int-спецификаторы-объявления; max(int a, int b, int с) - объявитель функции, a { ... } - блок, задающий ее код. Определение старым способом той же функции выглядит следующим образом:

int max(a, b, с) int а, b, с; { /* ... */ }

где max(a, b, c) – объявитель, а int a, b, c - список-объявлений для параметров.


Содержание раздела