Вы вошли на сайт, как Гость
Регистрация

Функции

Основы языка Си
(Функции)

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

Основная программа – это особый тип функции, ее отличие от других функций заключается в том, что она исполняется, когда запускают программу с определенным именем. Корректно написанная основная программа работает как программа «управленец» (менеджер высшего звена). Текст основной функции main.c отражает структуру всей прикладной программы, при этом не затрагивая специфических особенностей отдельных задач по управлению объектом. Мы можем представить основ ную программу в роли управляющего, который контролирует выполнение отдельных «команд» управления путем запуска программфункций. Предположим, что мы хотим выполнить задачи с первой по n-ую. Для этого оформлены n функций. Тогда мы запишем основную программу, в которой будут последовательно вызываться эти функции:

1 void main(void)
2 {
3 function_one();
4 function_two();
5 function_three();
6 :
7 :
8 :
9 function_n();
10 }

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

Любая функция перед тем, как в тексте программы будет записан ее программный код или оператор ее вызова, должна быть объявлена. Объявление функции в языке Си называют прототипом функции. Формат записи прототипа функции следующий:

<тип возвращаемой переменной>  <имя функции>
                               <тип переменной1> <имя переменной1>,
                               <тип переменной2> <имя переменной2>,
                               :
                               <тип переменнойN> <имя переменнойN>;

Имена переменных в круглых скобках приводить необязательно, но полезно для лучшего документирования. Обратите внимание на обязательное использование точки с запятой в конце записи прототипа. Приведем три примера прототипов функций:

Пример 1: int compute(int, int);
Пример 2: float change(char name, float number, int a);
Пример 3: double find(unsigned int, float, double);

В примере 1 функция compute использует два аргумента. Аргументы функции это те переменные, которые необходимы для ее корректного исполнения, Спецификация типа аргументов функции приведена в круглых скобках. В данном случае указано, что функция compute будет использовать два целочисленных аргумента, т.е. при вызове функции ей должны быть указаны для целочисленных значения. Резуль татом действия функции compute будет вычисление значения некоторой переменной. Спецификация типа возвращаемой переменной приведена перед именем функции. В данном случае это тоже целочисленный 16-разрядный формат. В примере 2 записан прототип функции change. Эта функция предполагает наличие трех аргументов: однобайтового целочисленного name, числа с именем number в формате с плавающей запятой и двухбайтового целого числа с именем a. Функция change должна возвратить значение переменной в формате с плавающей запятой. В примере 3 объявляется функция find с тремя аргументами, для которых указан тип данных, но не указаны имена. При знакомстве с программами на Си Вы можете встретить прототип функции, в котором на первом месте указано слово extern: extern not_here(int a, int b, int c). Подобная запись означает, что определение функции not_here не включено в текст данного программного модуля (текущего файла), а располагается во внешнем модуле (другом файле), который будут объединен с текущим модулем при составлении конечного исполняемого кода программы. Если функция была объявлена в тексте какого-либо программного модуля, то она должна быть определена в этом же модуле или другом модуле, например в файле библиотеки.

Каждая объявленная в начале некоторого программного модуля функция должна быть определена в этом модуле или в тексте программы другого модуля, который в процессе генерации исполняемого кода программы будет присоединен к текущему модулю. Функция может быть также определена в подключаемом файле стандартной библиотеки. Текст определения функции может быть записан в любом месте программного модуля, однако принято определения всех используемых функций располагать сразу за текстом основной программы main.c. Например, предположим, что объявленная в предыдущем параграфе функция compute вычисляет модуль вектора двух ортогональных составляющих a и b и возвращает его в переменной с именем result. Прототип функции: int compute(int a, int b). Определение функции начинается с комментария, в котором перечисляются производимые функцией действия. Далее следует повтор строки прототипа функции, но без заключительных точки с запятой. Ниже последовательно располагаются все операторы функции, которые сверху и снизу заключаются в фигурные скобки.

/*Функция compute: вычисляет модуль вектора по двум его ортогональным */
/*составляющим */
1 int compute(int a, int b)
2 {
3 int sum, result;
4 sum = a*a + b*b;
5 result=(int) (sqrt(sum));
6 return(result);
7 }

В приведенном примере строка 1 открывает определение функции, информируя компилятор о том, что имя функции compute, она использует для своей работы две целочисленных переменных и возвращает одну целочисленную переменную. Фигурная скобка в строке 2 открывает область операторов определяемой функции. В строке 3 объявляются локальные переменные, т.е. те переменные, которые используются только внутри функции. Это переменные sum и result. Операторы, расположенные в строках 4 и 5 выполняют заявленные в описании функции вычисления. Причем в строке 5 используется функция извлечения квадратного корня sqrt, которая определена в библиотеке математических вычислений. При компиляции эта библиотека должна быть обязательно присоединена к файлу с рассматриваемой функцией посредством специальных директив компилятора, которые мы рассмотрим в следующем параграфе. В строке 5 следует обратить внимание на оператор (int) перед вызовом функции извлечения квадратного корня. Этот оператор осуществляет преобразование типа данных к заявленному в прототипе функции compute целочисленному формату int, поскольку функция извлечения квадратного корня возвращает данные в другом формате. В строке 6 применен оператор возврата return, которые позволяет использовать значение переменной result другими операторами основной программы. Фигурная скобка в строке 7 завершает определение функции. Любые операторы, записанные после скобки, уже не будут ассоциироваться с функцией compute. На основании анализа примера Вам следует запомнить, что каждая функция должна быть определена в строго заданном формате исходного текста программы. Сначала следует строка прототипа функции, в которой указывается имя функции, используемые переменные и возвращаемые переменные. В отличие от строки объявления функции, точка с запятой в конце строки прототипа при определении функции не ставятся. Затем следуют операторы функции, заключенные в фигурные скобки. Если в поле возвращаемой переменной прототипа указан ее тип, то последним оператором функции должен быть оператор return. Если же в поле возвращаемой переменной прототипа стоит служебное слово void, то функция не возвращает данных. Назначение такой функции – выполнить определенный набор действий по управлению периферийными модулями МК или внешними устройствами. Соответственно и оператор return в последней строке отсутствует.