Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции_СП_2004_1_00.doc
Скачиваний:
69
Добавлен:
04.11.2018
Размер:
882.69 Кб
Скачать

3. Предварительное описание функций

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

<sc-specifier> <type-specifier> declarator (<arg-list>)

<, declarator(<arg-list>) ... >;

Здесь sc-specifier задает класс памяти (static или extern), который имеет вызываемая функция (см. Лекцию 7, $ 2), type-specifier устанавливает тип возвращаемого ей значения, а arg-list определяет количество и тип аргументов. Declarator в приведенной схеме является идентификатором функции, возможно модифицированным при помощи круглых скобок и символа звездочка для указателей на функции и функций, возвращающих указатели. Список аргументов arg-list обычно представляет собой последовательность разделенных запятыми имен типов данных, поддерживаемых имеющимся компилятором языка или предварительно определенных при помощи инструкции typedef (см. Лекцию 8, $ 8). Однако он также может содержать и обычные описания переменных вида float g. Использование ключевого слова void на месте arglist позволяет объвить функцию, не имеющую параметров. Поскольку функции в языке Си могут возвращать любые значения, кроме массивов и других функций, typespecifier может задавать любой простой тип данных, а также структуру, объединение или перечисление (см. Лекцию 8). В тех случаях, когда функция не вырабатывает никакого значения или возвращает указатель неопределенного типа (см. Лекцию 4, $ 1), ее предварительное описание должно начинаться с ключевого слова void, стоящего на месте имени типа возвращаемого значения. Введенное таким образом понятие предварительного описания функции дает возможность компилятору построить некоторый шаблон этой функции до ее фактического определения в текущем или внешнем файле. Этот шаблон может быть использован для контроля правильности типа возвращаемого функцией значения и соответствия формальных и фактических параметров. Ниже приведены несколько характерных примеров построения предварительных описаний.

1. В этом примере описана функция с именем add, возвращающая значение типа double и оба аргумента которой являются указателями на тип float:

double add(float*, float*);

2. Если функция с именем sum имеет два аргумента типа double и возвращает указатель на массив трех элементов типа double, то ее предварительное описание должно иметь следующий вид:

double (*sum(double, double))[3];

3. В том случае, когда функция не имеет аргументов и возврашает указатель неопределенного типа, в ее предварительном описании необходимо использовать ключевое слово void на месте имени типа возвращаемого значения и списка аргументов:

void *draw(void);