Встраиваемые системы. Проектирование приложений на микроконтроллерах семейства 68HC12/HCS12 с применением языка С
Шрифт:
В приведенном примере строка 1 открывает определение функции, информируя компилятор о том, что имя функции compute, она использует для своей работы две целочисленных переменных и возвращает одну целочисленную переменную. Фигурная скобка в строке 2 открывает область операторов определяемой функции. В строке 3 объявляются локальные переменные, т.е. те переменные, которые используются только внутри функции. Это переменные sum и result. Операторы, расположенные
На основании анализа примера Вам следует запомнить, что каждая функция должна быть определена в строго заданном формате исходного текста программы. Сначала следует строка прототипа функции, в которой указывается имя функции, используемые переменные и возвращаемые переменные. В отличие от строки объявления функции, точка с запятой в конце строки прототипа при определении функции не ставятся. Затем следуют операторы функции, заключенные в фигурные скобки. Если в поле возвращаемой переменной прототипа указан ее тип, то последним оператором функции должен быть оператор return. Если же в поле возвращаемой переменной прототипа стоит служебное слово void, то функция не возвращает данных. Назначение такой функции — выполнить определенный набор действий по управлению периферийными модулями МК или внешними устройствами. Соответственно и оператор return в последней строке отсутствует.
3.4.5. Вызов функций, передача параметров, возврат полученных значений
Если функция объявлена и определена, то она может быть вызвана из любой части программного модуля. Для вызова функции необходимо записать ее имя и в круглых скобках указать значения параметров, если таковые присутствовали в прототипе функции. Например, для вызова функции compute с двумя параметрами запишем выражение:
В этом примере мы предполагаем, что переменная magnitude ранее была объявлена как целочисленная. После того, как функция была вызвана и выполнена, переменной magnitude будет присвоено значение 26. Истинный результат вычисления равен 26,832816. Именно это значение будет вычислено функцией извлечения квадратного корня sqrt. Однако перед присвоением переменной result этого значения производится смена формата представления данных, и дробная часть результата отбрасывается.
Для того, чтобы функция могла произвести требуемые вычисления, ей должны были быть переданы два параметра, которые мы указали в круглых скобках. Число параметров и формат их представления указываются в прототипе функции. В прототипе функции compute было также заявлено, что функция возвращает одно целочисленное значение. А может ли функция вернуть сразу несколько значений? Да может, если Вы корректно запишете прототип и определение функции. Для этого необходимо познакомиться с понятиями указателя и структуры, которые мы рассмотрим несколько позже. А пока лишь заметим, что функция может возвратить некоторый набор вычисленных значений посредством возврата начального адреса этих данных в памяти. Такой подход предполагает, что следующие программные фрагменты должны «знать» последовательность расположения данных в строке с указанного адреса, т.е. знать структуру представления данных в строке.
3.5. Файлы заголовков
В этом параграфе мы расширим наши знания о технике программирования на Си посредством знакомства с заголовочными
Выражения языка С для включения файлов заголовков в модуль разрабатываемой программы обычно располагаются в начале программы. Заголовочные файлы содержат определения переменных, макросы, объявления функций, позволяя программисту возможность вызывать эти функции, использовать переменные и макросы без дополнительного определения их в тексте создаваемой программы. В процессе компиляции значения постоянных переменных замещают их символьные значения, упомянутые в основной программе. Далее в примерах программ мы будем использовать заголовочный файл stdio.h, в котором определены функции библиотеки стандартного ввода/вывода. Эти функции позволяют отобразить результаты преобразования данных в МК на экране дисплея. А также передать в МК код нажатой клавиши на клавиатуре. Поставляемые фирмами производителями программного обеспечения компиляторы уже содержат библиотеки и соответствующие им заголовочные файлы. Например, нами будет использована библиотека математических функций, и соответствующий ей файл math.h. Во многих случаях у пользователя возникает необходимость создания своего собственного заголовочного файла, в котором будут содержаться определения констант. Для того чтобы включить файл заголовка в разрабатываемый программный модуль, следует воспользоваться директивой #include. Приведем три примера:
В первых двух записях имя подключаемого файла заключено в «<>», что информирует компилятор о том, что названные файлы располагаются в определенной директории (папке). Обычно это папка с именем include, которая располагается в основном каталоге компилятора Си. В третьей записи имя подключаемого файла заключено в двойные кавычки. Для компилятора это означает, что данный файл располагается в той же папке, что и создаваемый программный модуль.
3.6. Директивы компилятора
Директивы компилятора — это инструкции для программы компилятора, которые указывают ему каким образом следует обрабатывать исходный текст программы. Достаточно часто эти инструкции называют директивами препроцессора компилятора, акцентируя внимание пользователей на том, что эти директивы выполняют обработку исходного текста программы перед тем, как компилятор начнет генерацию ассемблерного текста программы. Известно 11 директив компилятора Си: #if, #ifdef, #ifndef, #else, #elif, #include, #define, #undef, #line, #error, #pragma. Из приведенного списка понятно, что директивы отмечаются символом # в первом знаке имени. Далее мы рассмотрим наиболее часто используемые директивы.
3.6.1. Директивы условной компиляции
Директивы #if, #ifdef, #ifndef, #else, #elif и #endif относятся к группе директив условной компиляции. Эти директивы используются для того, чтобы обозначенный фрагмент исходного текста программы можно было бы включать или не включать в компилируемый код в зависимости от выполнения некоторого наперед заданного условия. Такое действие может быть полезным, например, в процессе отладки программы. Тогда в отладочной версии программы промежуточные результаты вычислений будут выводиться на экран дисплея, в рабочей версии эти действия выполняться не будут.
Директивы #if и #endif обязательно используются вместе, чтобы обозначить начало и конец условно компилируемого текста программы. В строке с директивой #if записывается условие компиляции. Если это условие выполняется, то выражения, записанные в программе между директивами #if и #endif включаются в компилируемый текст программы. В противном случае эти выражения исключаются из генерированного кода программы. Например, в процессе отладки мы хотим вывести на экран указанную в тексте программы фразу: