Представьте себе, что Вы работаете членом большой бригады инженеров, которой предстоит разработать программное обеспечение для встраиваемых систем самолета. Очевидно, что на начальной стадии проекта вся команда разработчиков должна пройти через те этапы структурного проектирования, которые были рассмотрены нами в главе 2. На завершающем этапе структурного проектирования, когда одна большая задача будет поделена на множество мелких, но функционально законченных фрагментов, каждому из членов команды будет поручено выполнение какого либо фрагмента общей программы. Эти фрагменты оформляются как функции, из которых впоследствии будет состоять большая программа.
В соответствии с приведенной стратегией составления большой программы, каждая функция должна обладать тремя свойствами: независимостью, гибкостью и переносимостью. Функция должна быть относительно независима от другого программного кода, поскольку эта функция в дальнейшем может быть использована различными программистами в данном проекте или даже в другом проекте. Возвращаясь к примеру, предположим, что Вам предложили написать функцию, которая устраняет шумовую составляющую входного аналогового сигнала (цифровой фильтр). Ваша программа цифрового фильтра будет использоваться многими соисполнителями проекта для устранения шума различных входных сигналов. Следовательно, Ваша программа, оформленная как функция, должна обеспечивать возможность ее вызова из любого места большой программы (свойство независимости) и должна легко настраиваться на прием сигнала с различных портов МК (свойство гибкости). Термин «относительно независима» в начале этого параграфа мы применили потому, что функция может получать от ранее исполненного программного кода некоторые численные значения, которые будет использовать при своей работе. Например, в Вашу функцию могут передаваться имя порта ввода и номер линии, на которой присутствует сигнал, который подлежит цифровой фильтрации. Вы значительно увеличите гибкость своего решения, если предусмотрите возможность изменения частотного диапазона шумовой составляющей сигнала, которая будет устранена после исполнения программного кода Вашей функции.
И, наконец, о свойстве переносимости. В рассматриваемом примере управления самолетом, многочисленные встраиваемые системы могут быть выполнены на разной элементной базе, в том числе на МК с различным процессорным ядром, и даже от разных производителей. При этом крайне желательно, чтобы разработанные специалистом функции цифровой фильтрации могли быть использованы во всех решениях. Поэтому следует написать исходный текст программы на Си таким образом, чтобы он не был ориентирован на специальные команды процессорного ядра, и мог быть обработан любым компилятором языка Си из перечня используемых в проекте.
3.4.2. Основная программа
Основная программа — это особый тип функции, ее отличие от других функций заключается в том, что она исполняется, когда запускают программу с определенным именем. Корректно написанная основная программа работает как программа «управленец» (менеджер высшего звена). Текст основной функции 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 и так до конца программного фрагмента.
3.4.3. Прототипы функций
Любая функция перед тем, как в тексте программы будет записан ее программный код или оператор ее вызова, должна быть объявлена. Объявление функции в языке Си называют прототипом функции. Формат записи прототипа функции следующий:
тип возвращаемой переменной имя функции
(<тип переменной1> <имя переменной1>,
<тип переменной2> <имя переменной2>,
:
<тип переменной> <имя переменнойN>);
Имена переменных в круглых скобках приводить необязательно, но полезно для лучшего документирования. Обратите внимание на обязательное использование точки с запятой в конце записи прототипа. Приведем три примера прототипов функций: