Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Уч. пос. МПТ (2.04.12).pdf
Скачиваний:
404
Добавлен:
22.03.2015
Размер:
10.95 Mб
Скачать

Таблица 2.1.4 – Представление и неопределенности в формате IEEE754

Десятичное

Чисто в формате IEEE754

 

P

P

(двоичный код,

M

одинарная

двойная

число

одинарная точность)

 

точность

точность

 

 

0

 

0

0

0

 

 

 

 

 

 

 

0

0

0

 

 

 

 

 

 

 

0

255

1023

 

 

 

 

 

неопреде-

 

> 0

255

1023

ленность

 

 

 

 

 

 

 

 

 

 

2.2 Основы программирования на языке Си

Си является основным языком программирования встраиваемых систем. В настоящее время разработано множество Си-компиляторов для большинства архитектур: от простейших 8-разрядных микроконтроллеров PIC18 (Microchip) и AVR (Atmel), до развитых сигнальных процессоров Analog Devices и Texas Instruments.

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

Применение одного языка при разработке программ для персонального компьютера и встраиваемой системы облегчает их сопряжение благодаря одинаковым форматам хранения данных.

Недостатком программирования на Си является некоторое снижение производительности. Чаще всего это не создает проблем, из-за постоянно растущего быстродействия современных микроконтроллеров. К тому же, как правило, допускается внедрение в Си-программу блоков, составленных на ассемблере (см. раздел 22).

В этом разделе будут коротко рассмотрены основы программирования на Си. При этом, как было сказано выше, ориентируемся на компилятор RealView 4. В то же время материал вполне соответствует стандарту ANSI и в основном может использоваться при работе с другими компиляторами.

Для углубленного изучения языка авторы рекомендуют пользоваться известными учебниками [3, 4].

101

2.2.1 Структура программы

Упрощено структуру программы на языке Си можно показать так:

Директивы компилятора Объявление глобальных переменных

Объявление функций и процедур обработки прерываний int main()

{

Объявление локальных переменных основной программы Блок, выполняемый однажды

while (1)

{

Блок, выполняемый циклически

}

}

Программа обычно начинается с одной или нескольких директив компилятора, например, предназначенных для подключения стандартных библиотек. Далее следует раздел объявления глобальных переменных. Функции и процедуры обработки прерываний включаются в программу до основной программы. Основная программа и каждая функция может иметь раздел объявления локальных переменных.

Комментарии обозначаются двумя способами. Однострочные комментарии начинаются с двух символов «слэш»

// Однострочный комментарий

Многострочный комментарий начинается символами «/*» и заканчивается теми же символами в обратном порядке «*/»

/*

Многострочный комментарий

*/

Символы после «//» до конца строки, а также между «/* */» игнорируются компилятором.

2.2.2 Числовые константы

Целочисленные константы записываются в десятичной, восьмеричной или шестнадцатеричной системе счисления. Восьмеричные числа начинаются с нуля; шестнадцатеричные обозначаются предшествующими символами 0x.

Символьная константа (один символ, заключенный в апострофы) является тоже, на самом деле, является числовой. Вместо символа подставляется его ASCII-код размером 1 байт. Символ соответствует типу char.

Ниже предложены несколько примеров записи целочисленных констант, причем, идентичных с точки зрения машинного представления.

90 // Десятичное число 90 0132 // Число 90, представленное в 8-ричной форме

0x5A // Число 90, представленное в 16-ричной форме 'Z' // Символ Z, с кодом 90

102

Дробные (вещественные) числа записываются через точку, отделяющую целую часть от дробной, либо в экспоненциальном формате. Например, следующие две записи эквивалентны

0.00125

12.5E–4 // 12.5*10^(-4)=0.00125

2.2.3 Переменные и именованные константы

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

Тип Имя1, Имя2, ... ;

или

Тип Имя1 = Значение1, Имя2 = Значение2, ... ;

Здесь Тип — один из типов данных, рассмотренных в разделах 2.1.2, 2.1.3; Имя — идентификатор (имя переменной); Значение — значение, которое будет присвоено переменой по умолчанию (указывать не обязательно). Допускается через запятую перечислять несколько однотипных переменных.

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

Пример объявления четырех переменных с именами Var1–Var4:

char Var1;

unsigned int Var2=0x80000000, Var3=0; float Var4=7.5;

Блок объявления переменных может быть расположен:

1)до основной программы (объявление глобальных переменных);

2)в начале основной программы (первая запись после открывающейся операторной скобки «{»);

3)в начале каждой функции.

В зависимости от того, где объявлены переменные, они являются глобальными (доступны в любой функции) или локальными (доступны в пределах функции или основной программы). Первый вариант размещения дает глобальные переменные, второй и третий — локальные. Если локальных переменных немного, компилятор использует для их хранения регистры общего назначения R0–R12. Это сокращает расход памяти и увеличивает быстродействие программы. Поэтому локальным переменным следует отдавать предпочтение.

Помимо переменных могут также использоваться именованные константы. Объявляются они также, но с ключевым словом const.

const Тип Имя1 = Значение1, Имя2 = Значение2, ... ;

Пример:

const double pi=3.141592653589793238462643383;

Так можно создавать массивы данных, объем которых превышает объем оперативной памяти. Константы при этом размещаются в ПЗУ.

103

2.2.4 Оператор присваивания, выражения и операции

Общая форма оператора присваивания такова

Переменная = Выражение ;

Допустимо присваивание нескольким переменным одного и того же значения в одном операторе

Переменная1 = Переменная2 = ... = Выражение ;

Выражения конструируются с участием других переменных, числовых констант и знаков арифметических и логических операций. Выполнение операций выполняется в порядке их приоритетов.

Основные операции с комментариями и примерами приведены в таблице 2.2.1. В правой колонке указаны приоритеты операций (1 — самый высокий, 12 — самый низкий). Для изменения приоритета, как обычно, служат круглые скобки «( )». Операции над выражениями в скобках имеют первый (высший) приоритет.

Часто новое значение переменной рассчитывается с использованием старого. Тогда одна и та же переменная оказывается и слева, и справа от знака присваивания. В этом случае удобна сокращенная форма записи оператора присваивания, которая имеет следующий общий вид.

Переменная Операция = Выражение ;

Эта запись тождественна следующей привычной форме

Переменная = Переменная Операция (Выражение) ;

Здесь скобки показывают, что какой бы ни была Операция, Выражение вычисляется в первую очередь, потому что сокращенная форма имеет низший 14-ый приоритет. В качестве примера рассмотрим две команды, которые дадут одинаковый результат.

A=A*(B+С);

A*=B+С;

2.2.5 Условный оператор

Условный оператор предназначен для выбора одного из выражений в зависимости от некоторого условия. Обычно с целью присваивания. Форма записи условного оператора следующая

Условие ? Выражение1 : Выражение2 ;

Результатом является Выражение1, если Условие не равно нулю. В противном случае, результат — Выражение2.

Приведем пример.

A=B+(C<0?-1:1);

Здесь переменной A будет присвоено значение B, увеличенное или уменьшенное на единицу в зависимости от знака переменной C.

2.2.6 Приведение и преобразование типов

Если в выражении участвуют операнды разных типов, то они приводятся к одному типу по следующим правилам:

104

Таблица 2.2.1 – Основные операторы языка Си

Опер.

Описание

Пример

Примечание

Приор.

*

Обращение по адресу

*A

Обращение к данным, по адресу в указателе

2

&

Взятие адреса

&A

Возвращает 32-разрядный адрес переменной или константы

2

!

Логическое НЕ

!A

Результат 1, если операнд равен 0, иначе 0

 

2

~

Поразрядное НЕ

~A

 

2

++

Инкремент

++A или A++

Увеличение операнда на 1 до или после использования

2

––

Декремент

––A или A––

Уменьшение операнда на 1 до или после использования

2

*

Умножение

A * B

 

3

/

Деление

A / B

Для целочисленных операндов дает целую часть от деления,

3

округленную до меньшего по модулю

 

 

 

 

%

Остаток от деления

A % B

Только для целочисленных операндов

3

+

Арифметическое сложение

A + B

 

4

Арифметич. вычитание

A – B

 

4

>>

Сдвиг вправо

A >> B

Второй операнд обозначает число разрядов сдвига

5

<<

Сдвиг влево

A << B

5

 

>

Больше

A > B

 

6

<

Меньше

A < B

Результат 1, если неравенство справедливо, иначе 0

6

>=

Больше или равно

A >= B

6

 

<=

Меньше или равно

A <= B

 

6

==

Равно

A == B

Результат 1, если неравенство или равенство

7

!=

Не равно

A != B

справедливо, иначе 0

7

&

Поразрядное И

A & B

 

8

^

Поразрядное исключ. ИЛИ

A ^ B

 

9

|

Поразрядное ИЛИ

A | B

 

10

&&

Логическое И

A && B

Результат 1, если оба операнда не равны 0, иначе 0

11

||

Логическое ИЛИ

A || B

Результат 1, если один из операндов не равен 0, иначе 0

12

105

1.Приведение типов выполняется попарно в порядке приоритетов операций. То есть, сначала приводятся типы операндов связанных операцией

снаивысшим приоритетом.

2.Если в операции участвуют знаковые и беззнаковые операнды, результат приводится к беззнаковому типу. Знак теряется.

3.Если в операции участвуют операнды разной длины, то результат будет иметь длину наибольшего из операндов. Правило касается как чисел с фиксированной точкой, так и с плавающей.

4.Если в операции участвуют операнды с фиксированной и с плавающей точкой, результат приводится к формату с плавающей точкой.

Пример 1:

int A=75, B=10;

 

double C;

 

...

 

C=A/B;

// C=7

Здесь операнды имеют один и тот же тип. Поэтому преобразование типов не производится, несмотря на то, что для сохранения результата деления без потерь информации необходим формат с плавающей точкой.

Нередко это становится причиной ошибок даже с константами.

X=Y/2;

даст всегда целый результат, потому что 2 интерпретируется как целочисленная константа, в то время как

X=Y/2.0;

дает дробный результат, если X вещественного типа (float или double).

Пример 2:

int A=–1;

unsigned int B=10; double C=1, D;

...

D=A*B*C; // D=4294967286

Результат умножения A*B в соответствии с правилом 2 получает беззнаковый тип. В то же время изменение порядка множителей даст другой результат.

int A=–1;

unsigned int B=10; double C=1, D;

...

 

D=C*A*B;

// D=–10

Результат умножения C*A в соответствии с правилом 4 сразу приводится к формату с плавающей точкой, поэтому в дальнейшем потери знака не происходит.

В рамках выражения можно принудительно преобразовать тип одного из операндов или части выражения, указав перед ним тип в скобках.

int A=–1;

106